3eb3c87fmKYTC5GCh_rydFakZp9ayw xen/tools/figlet/README
3eb3c87fdQKQ5OBGbM-KjZfi9Us4ng xen/tools/figlet/figlet.c
3eb3c87fS7DNbg0i6yhFs28UIqAK5g xen/tools/figlet/xen.flf
-3e5a4e6589G-U42lFKs43plskXoFxQ xenolinux-2.4.21-pre4-sparse/Makefile
-3e5a4e65IEPjnWPZ5w3TxS5scV8Ewg xenolinux-2.4.21-pre4-sparse/arch/xeno/Makefile
-3e5a4e65n-KhsEAs-A4ULiStBp-r6w xenolinux-2.4.21-pre4-sparse/arch/xeno/boot/Makefile
-3e5a4e65OV_j_DBtjzt5vej771AJsA xenolinux-2.4.21-pre4-sparse/arch/xeno/config.in
-3e5a4e65TNEycLeXqPSXQJQm_xGecA xenolinux-2.4.21-pre4-sparse/arch/xeno/defconfig
-3e6377f5xwPfYZkPHPrDbEq1PRN7uQ xenolinux-2.4.21-pre4-sparse/arch/xeno/drivers/balloon/Makefile
-3e6377f8Me8IqtvEhb70XFgOvqQH7A xenolinux-2.4.21-pre4-sparse/arch/xeno/drivers/balloon/balloon.c
-3e6377fbMjXWAQd0XN0FWv4fDEo6fg xenolinux-2.4.21-pre4-sparse/arch/xeno/drivers/balloon/dom_mem_ops.h
-3e5a4e65iHEuC5sjFhj42XALYbLVRw xenolinux-2.4.21-pre4-sparse/arch/xeno/drivers/block/Makefile
-3e5a4e65pP5spJErBW69pJxSSdK9RA xenolinux-2.4.21-pre4-sparse/arch/xeno/drivers/block/xl_block.c
-3e67f822FOPwqHiaRKbrskgWgoNL5g xenolinux-2.4.21-pre4-sparse/arch/xeno/drivers/block/xl_block.h
-3e677190SjkzJIvFifRVeYpIZOCtYA xenolinux-2.4.21-pre4-sparse/arch/xeno/drivers/block/xl_ide.c
-3e677193nOKKTLJzcAu4SYdbZaia8g xenolinux-2.4.21-pre4-sparse/arch/xeno/drivers/block/xl_scsi.c
-3e676eb5RXnHzSHgA1BvM0B1aIm4qg xenolinux-2.4.21-pre4-sparse/arch/xeno/drivers/block/xl_segment.c
-3e5d129aDldt6geU2-2SzBae34sQzg xenolinux-2.4.21-pre4-sparse/arch/xeno/drivers/block/xl_segment_proc.c
-3e5a4e65G3e2s0ghPMgiJ-gBTUJ0uQ xenolinux-2.4.21-pre4-sparse/arch/xeno/drivers/console/Makefile
-3e5a4e651TH-SXHoufurnWjgl5bfOA xenolinux-2.4.21-pre4-sparse/arch/xeno/drivers/console/console.c
-3e5a4e656nfFISThfbyXQOA6HN6YHw xenolinux-2.4.21-pre4-sparse/arch/xeno/drivers/dom0/Makefile
-3e5a4e65Cc7io-vynYob10SlqXTjAQ xenolinux-2.4.21-pre4-sparse/arch/xeno/drivers/dom0/dom0_block.c
-3e5a4e65BXtftInNHUC2PjDfPhdZZA xenolinux-2.4.21-pre4-sparse/arch/xeno/drivers/dom0/dom0_core.c
-3e5a4e65uXAx05p6B1-HU2tijuw8qA xenolinux-2.4.21-pre4-sparse/arch/xeno/drivers/dom0/dom0_memory.c
-3e5a4e65EOOLlPwXnhSuX-iVdWLmnA xenolinux-2.4.21-pre4-sparse/arch/xeno/drivers/dom0/dom0_ops.h
-3e6dba59C8o0kBks7UZ4IW_FY853Aw xenolinux-2.4.21-pre4-sparse/arch/xeno/drivers/dom0/sched_ops.c
-3e5a4e65gfn_ltB8ujHMVFApnTTNRQ xenolinux-2.4.21-pre4-sparse/arch/xeno/drivers/dom0/vfr.c
-3e5a4e65gZBRBB6RsSVg1c9iahigAw xenolinux-2.4.21-pre4-sparse/arch/xeno/drivers/network/Makefile
-3e5a4e65ZxKrbFetVB84JhrTyZ1YuQ xenolinux-2.4.21-pre4-sparse/arch/xeno/drivers/network/network.c
-3e5a4e65lWzkiPXsZdzPt2RNnJGG1g xenolinux-2.4.21-pre4-sparse/arch/xeno/kernel/Makefile
-3e5a4e65_hqfuxtGG8IUy6wRM86Ecg xenolinux-2.4.21-pre4-sparse/arch/xeno/kernel/entry.S
-3e5a4e65Hy_1iUvMTPsNqGNXd9uFpg xenolinux-2.4.21-pre4-sparse/arch/xeno/kernel/head.S
-3e5a4e65ibVQmwlOn0j3sVH_j_6hAg xenolinux-2.4.21-pre4-sparse/arch/xeno/kernel/hypervisor.c
-3e5a4e65RMGcuA-HCn3-wNx3fFQwdg xenolinux-2.4.21-pre4-sparse/arch/xeno/kernel/i386_ksyms.c
-3e5a4e65MEvZhlr070sK5JsfAQlv7Q xenolinux-2.4.21-pre4-sparse/arch/xeno/kernel/ioport.c
-3e5a4e653U6cELGv528IxOLHvCq8iA xenolinux-2.4.21-pre4-sparse/arch/xeno/kernel/irq.c
-3e5a4e65muT6SU3ck47IP87Q7Ti5hA xenolinux-2.4.21-pre4-sparse/arch/xeno/kernel/ldt.c
-3e5a4e65IGt3WwQDNiL4h-gYWgNTWQ xenolinux-2.4.21-pre4-sparse/arch/xeno/kernel/process.c
-3e5a4e66tR-qJMLj3MppcKqmvuI2XQ xenolinux-2.4.21-pre4-sparse/arch/xeno/kernel/setup.c
-3e5a4e66fWSTagLGU2P8BGFGRjhDiw xenolinux-2.4.21-pre4-sparse/arch/xeno/kernel/signal.c
-3e5a4e66N__lUXNwzQ-eADRzK9LXuQ xenolinux-2.4.21-pre4-sparse/arch/xeno/kernel/time.c
-3e5a4e66aHCbQ_F5QZ8VeyikLmuRZQ xenolinux-2.4.21-pre4-sparse/arch/xeno/kernel/traps.c
-3e5a4e66-9_NczrVMbuQkoSLyXckIw xenolinux-2.4.21-pre4-sparse/arch/xeno/lib/Makefile
-3e5a4e6637ZDk0BvFEC-aFQs599-ng xenolinux-2.4.21-pre4-sparse/arch/xeno/lib/delay.c
-3e5a4e66croVgpcJyJuF2ycQw0HuJw xenolinux-2.4.21-pre4-sparse/arch/xeno/mm/Makefile
-3e5a4e66l8Q5Tv-6B3lQIRmaVbFPzg xenolinux-2.4.21-pre4-sparse/arch/xeno/mm/fault.c
-3e5a4e66TyNNUEXkr5RxqvQhXK1MQA xenolinux-2.4.21-pre4-sparse/arch/xeno/mm/get_unmapped_area.c
-3e5a4e668SE9rixq4ahho9rNhLUUFQ xenolinux-2.4.21-pre4-sparse/arch/xeno/mm/hypervisor.c
-3e5a4e661gLzzff25pJooKIIWe7IWg xenolinux-2.4.21-pre4-sparse/arch/xeno/mm/init.c
-3e5a4e66U45cAIoHmxg0y1e1XhzVCA xenolinux-2.4.21-pre4-sparse/arch/xeno/mm/mmu_context.c
-3e5a4e66qRlSTcjafidMB6ulECADvg xenolinux-2.4.21-pre4-sparse/arch/xeno/vmlinux.lds
-3ea53c6em6uzVHSiGqrbbAVofyRY_g xenolinux-2.4.21-pre4-sparse/drivers/block/genhd.c
-3e5a4e66mrtlmV75L1tjKDg8RaM5gA xenolinux-2.4.21-pre4-sparse/drivers/block/ll_rw_blk.c
-3e5a4e66rw65CxyolW9PKz4GG42RcA xenolinux-2.4.21-pre4-sparse/drivers/char/tty_io.c
-3e5a4e669uzIE54VwucPYtGwXLAbzA xenolinux-2.4.21-pre4-sparse/fs/exec.c
-3e5a4e66wbeCpsJgVf_U8Jde-CNcsA xenolinux-2.4.21-pre4-sparse/include/asm-xeno/bugs.h
-3e5a4e66HdSkvIV6SJ1evG_xmTmXHA xenolinux-2.4.21-pre4-sparse/include/asm-xeno/desc.h
-3e5a4e66SYp_UpAVcF8Lc1wa3Qtgzw xenolinux-2.4.21-pre4-sparse/include/asm-xeno/fixmap.h
-3e5a4e67w_DWgjIJ17Tlossu1LGujQ xenolinux-2.4.21-pre4-sparse/include/asm-xeno/highmem.h
-3e5a4e67YtcyDLQsShhCfQwPSELfvA xenolinux-2.4.21-pre4-sparse/include/asm-xeno/hw_irq.h
-3e5a4e677VBavzM1UZIEcH1B-RlXMA xenolinux-2.4.21-pre4-sparse/include/asm-xeno/hypervisor.h
-3e5a4e67Ulv-Ll8Zp4j2GwMwQ8aAXQ xenolinux-2.4.21-pre4-sparse/include/asm-xeno/io.h
-3e5a4e673p7PEOyHFm3nHkYX6HQYBg xenolinux-2.4.21-pre4-sparse/include/asm-xeno/irq.h
-3ead095db_LRUXnxaqs0dA1DWhPoQQ xenolinux-2.4.21-pre4-sparse/include/asm-xeno/keyboard.h
-3e5a4e67zoNch27qYhEBpr2k6SABOg xenolinux-2.4.21-pre4-sparse/include/asm-xeno/mmu.h
-3e5a4e678ddsQOpbSiRdy1GRcDc9WA xenolinux-2.4.21-pre4-sparse/include/asm-xeno/mmu_context.h
-3e7270deQqtGPSnFxcW4AvJZuTUWfg xenolinux-2.4.21-pre4-sparse/include/asm-xeno/multicall.h
-3e5a4e67mnQfh-R8KcQCaVo2Oho6yg xenolinux-2.4.21-pre4-sparse/include/asm-xeno/page.h
-3e5a4e67uTYU5oEnIDjxuaez8njjqg xenolinux-2.4.21-pre4-sparse/include/asm-xeno/pgalloc.h
-3e5a4e67X7JyupgdYkgDX19Huj2sAw xenolinux-2.4.21-pre4-sparse/include/asm-xeno/pgtable-2level.h
-3e5a4e67gr4NLGtQ5CvSLimMYZlkOA xenolinux-2.4.21-pre4-sparse/include/asm-xeno/pgtable.h
-3e5a4e676uK4xErTBDH6XJREn9LSyg xenolinux-2.4.21-pre4-sparse/include/asm-xeno/processor.h
-3e5a4e67AJPjW-zL7p-xWuA6IVeH1g xenolinux-2.4.21-pre4-sparse/include/asm-xeno/ptrace.h
-3e5a4e68uJz-xI0IBVMD7xRLQKJDFg xenolinux-2.4.21-pre4-sparse/include/asm-xeno/segment.h
-3e5a4e68Nfdh6QcOKUTGCaYkf2LmYA xenolinux-2.4.21-pre4-sparse/include/asm-xeno/smp.h
-3e5a4e68mTr0zcp9SXDbnd-XLrrfxw xenolinux-2.4.21-pre4-sparse/include/asm-xeno/system.h
-3e5a4e68WLX3B8owTvktP3HHOtznPQ xenolinux-2.4.21-pre4-sparse/include/linux/major.h
-3e5a4e686V0nioX2ZpFf056sgvdiQw xenolinux-2.4.21-pre4-sparse/include/linux/sunrpc/debug.h
-3e5a4e68W_hpMlM3u_-QOKMp3gzcwQ xenolinux-2.4.21-pre4-sparse/init/do_mounts.c
-3e5a4e68TJJavrunYwTAnLRSBxSYqQ xenolinux-2.4.21-pre4-sparse/kernel/panic.c
-3eba8f878XjouY21EkQBXwYBsPsipQ xenolinux-2.4.21-pre4-sparse/lndir-rel
-3e6e7c1efbQe93xCvOpOVCnXTMmQ5w xenolinux-2.4.21-pre4-sparse/mkbuildtree
-3e5a4e68GxCIaFH4sy01v1wjapetaA xenolinux-2.4.21-pre4-sparse/mm/memory.c
-3e5a4e681xMPdF9xCMwpyfuYMySU5g xenolinux-2.4.21-pre4-sparse/mm/mremap.c
-3e5a4e683HKVU-sxtagrDasRB8eBVw xenolinux-2.4.21-pre4-sparse/mm/swapfile.c
+3e5a4e6589G-U42lFKs43plskXoFxQ xenolinux-2.4.21-sparse/Makefile
+3e5a4e65IEPjnWPZ5w3TxS5scV8Ewg xenolinux-2.4.21-sparse/arch/xeno/Makefile
+3e5a4e65n-KhsEAs-A4ULiStBp-r6w xenolinux-2.4.21-sparse/arch/xeno/boot/Makefile
+3e5a4e65OV_j_DBtjzt5vej771AJsA xenolinux-2.4.21-sparse/arch/xeno/config.in
+3e5a4e65TNEycLeXqPSXQJQm_xGecA xenolinux-2.4.21-sparse/arch/xeno/defconfig
+3e6377f5xwPfYZkPHPrDbEq1PRN7uQ xenolinux-2.4.21-sparse/arch/xeno/drivers/balloon/Makefile
+3e6377f8Me8IqtvEhb70XFgOvqQH7A xenolinux-2.4.21-sparse/arch/xeno/drivers/balloon/balloon.c
+3e6377fbMjXWAQd0XN0FWv4fDEo6fg xenolinux-2.4.21-sparse/arch/xeno/drivers/balloon/dom_mem_ops.h
+3e5a4e65iHEuC5sjFhj42XALYbLVRw xenolinux-2.4.21-sparse/arch/xeno/drivers/block/Makefile
+3e5a4e65pP5spJErBW69pJxSSdK9RA xenolinux-2.4.21-sparse/arch/xeno/drivers/block/xl_block.c
+3e67f822FOPwqHiaRKbrskgWgoNL5g xenolinux-2.4.21-sparse/arch/xeno/drivers/block/xl_block.h
+3e677190SjkzJIvFifRVeYpIZOCtYA xenolinux-2.4.21-sparse/arch/xeno/drivers/block/xl_ide.c
+3e677193nOKKTLJzcAu4SYdbZaia8g xenolinux-2.4.21-sparse/arch/xeno/drivers/block/xl_scsi.c
+3e676eb5RXnHzSHgA1BvM0B1aIm4qg xenolinux-2.4.21-sparse/arch/xeno/drivers/block/xl_segment.c
+3e5d129aDldt6geU2-2SzBae34sQzg xenolinux-2.4.21-sparse/arch/xeno/drivers/block/xl_segment_proc.c
+3e5a4e65G3e2s0ghPMgiJ-gBTUJ0uQ xenolinux-2.4.21-sparse/arch/xeno/drivers/console/Makefile
+3e5a4e651TH-SXHoufurnWjgl5bfOA xenolinux-2.4.21-sparse/arch/xeno/drivers/console/console.c
+3e5a4e656nfFISThfbyXQOA6HN6YHw xenolinux-2.4.21-sparse/arch/xeno/drivers/dom0/Makefile
+3e5a4e65Cc7io-vynYob10SlqXTjAQ xenolinux-2.4.21-sparse/arch/xeno/drivers/dom0/dom0_block.c
+3e5a4e65BXtftInNHUC2PjDfPhdZZA xenolinux-2.4.21-sparse/arch/xeno/drivers/dom0/dom0_core.c
+3e5a4e65uXAx05p6B1-HU2tijuw8qA xenolinux-2.4.21-sparse/arch/xeno/drivers/dom0/dom0_memory.c
+3e5a4e65EOOLlPwXnhSuX-iVdWLmnA xenolinux-2.4.21-sparse/arch/xeno/drivers/dom0/dom0_ops.h
+3e6dba59C8o0kBks7UZ4IW_FY853Aw xenolinux-2.4.21-sparse/arch/xeno/drivers/dom0/sched_ops.c
+3e5a4e65gfn_ltB8ujHMVFApnTTNRQ xenolinux-2.4.21-sparse/arch/xeno/drivers/dom0/vfr.c
+3e5a4e65gZBRBB6RsSVg1c9iahigAw xenolinux-2.4.21-sparse/arch/xeno/drivers/network/Makefile
+3e5a4e65ZxKrbFetVB84JhrTyZ1YuQ xenolinux-2.4.21-sparse/arch/xeno/drivers/network/network.c
+3e5a4e65lWzkiPXsZdzPt2RNnJGG1g xenolinux-2.4.21-sparse/arch/xeno/kernel/Makefile
+3e5a4e65_hqfuxtGG8IUy6wRM86Ecg xenolinux-2.4.21-sparse/arch/xeno/kernel/entry.S
+3e5a4e65Hy_1iUvMTPsNqGNXd9uFpg xenolinux-2.4.21-sparse/arch/xeno/kernel/head.S
+3e5a4e65ibVQmwlOn0j3sVH_j_6hAg xenolinux-2.4.21-sparse/arch/xeno/kernel/hypervisor.c
+3e5a4e65RMGcuA-HCn3-wNx3fFQwdg xenolinux-2.4.21-sparse/arch/xeno/kernel/i386_ksyms.c
+3e5a4e65MEvZhlr070sK5JsfAQlv7Q xenolinux-2.4.21-sparse/arch/xeno/kernel/ioport.c
+3e5a4e653U6cELGv528IxOLHvCq8iA xenolinux-2.4.21-sparse/arch/xeno/kernel/irq.c
+3e5a4e65muT6SU3ck47IP87Q7Ti5hA xenolinux-2.4.21-sparse/arch/xeno/kernel/ldt.c
+3e5a4e65IGt3WwQDNiL4h-gYWgNTWQ xenolinux-2.4.21-sparse/arch/xeno/kernel/process.c
+3e5a4e66tR-qJMLj3MppcKqmvuI2XQ xenolinux-2.4.21-sparse/arch/xeno/kernel/setup.c
+3e5a4e66fWSTagLGU2P8BGFGRjhDiw xenolinux-2.4.21-sparse/arch/xeno/kernel/signal.c
+3e5a4e66N__lUXNwzQ-eADRzK9LXuQ xenolinux-2.4.21-sparse/arch/xeno/kernel/time.c
+3e5a4e66aHCbQ_F5QZ8VeyikLmuRZQ xenolinux-2.4.21-sparse/arch/xeno/kernel/traps.c
+3e5a4e66-9_NczrVMbuQkoSLyXckIw xenolinux-2.4.21-sparse/arch/xeno/lib/Makefile
+3e5a4e6637ZDk0BvFEC-aFQs599-ng xenolinux-2.4.21-sparse/arch/xeno/lib/delay.c
+3e5a4e66croVgpcJyJuF2ycQw0HuJw xenolinux-2.4.21-sparse/arch/xeno/mm/Makefile
+3e5a4e66l8Q5Tv-6B3lQIRmaVbFPzg xenolinux-2.4.21-sparse/arch/xeno/mm/fault.c
+3e5a4e66TyNNUEXkr5RxqvQhXK1MQA xenolinux-2.4.21-sparse/arch/xeno/mm/get_unmapped_area.c
+3e5a4e668SE9rixq4ahho9rNhLUUFQ xenolinux-2.4.21-sparse/arch/xeno/mm/hypervisor.c
+3e5a4e661gLzzff25pJooKIIWe7IWg xenolinux-2.4.21-sparse/arch/xeno/mm/init.c
+3e5a4e66U45cAIoHmxg0y1e1XhzVCA xenolinux-2.4.21-sparse/arch/xeno/mm/mmu_context.c
+3e5a4e66qRlSTcjafidMB6ulECADvg xenolinux-2.4.21-sparse/arch/xeno/vmlinux.lds
+3ea53c6em6uzVHSiGqrbbAVofyRY_g xenolinux-2.4.21-sparse/drivers/block/genhd.c
+3e5a4e66mrtlmV75L1tjKDg8RaM5gA xenolinux-2.4.21-sparse/drivers/block/ll_rw_blk.c
+3e5a4e66rw65CxyolW9PKz4GG42RcA xenolinux-2.4.21-sparse/drivers/char/tty_io.c
+3e5a4e669uzIE54VwucPYtGwXLAbzA xenolinux-2.4.21-sparse/fs/exec.c
+3e5a4e66wbeCpsJgVf_U8Jde-CNcsA xenolinux-2.4.21-sparse/include/asm-xeno/bugs.h
+3e5a4e66HdSkvIV6SJ1evG_xmTmXHA xenolinux-2.4.21-sparse/include/asm-xeno/desc.h
+3e5a4e66SYp_UpAVcF8Lc1wa3Qtgzw xenolinux-2.4.21-sparse/include/asm-xeno/fixmap.h
+3e5a4e67w_DWgjIJ17Tlossu1LGujQ xenolinux-2.4.21-sparse/include/asm-xeno/highmem.h
+3e5a4e67YtcyDLQsShhCfQwPSELfvA xenolinux-2.4.21-sparse/include/asm-xeno/hw_irq.h
+3e5a4e677VBavzM1UZIEcH1B-RlXMA xenolinux-2.4.21-sparse/include/asm-xeno/hypervisor.h
+3e5a4e67Ulv-Ll8Zp4j2GwMwQ8aAXQ xenolinux-2.4.21-sparse/include/asm-xeno/io.h
+3e5a4e673p7PEOyHFm3nHkYX6HQYBg xenolinux-2.4.21-sparse/include/asm-xeno/irq.h
+3ead095db_LRUXnxaqs0dA1DWhPoQQ xenolinux-2.4.21-sparse/include/asm-xeno/keyboard.h
+3e5a4e67zoNch27qYhEBpr2k6SABOg xenolinux-2.4.21-sparse/include/asm-xeno/mmu.h
+3e5a4e678ddsQOpbSiRdy1GRcDc9WA xenolinux-2.4.21-sparse/include/asm-xeno/mmu_context.h
+3e7270deQqtGPSnFxcW4AvJZuTUWfg xenolinux-2.4.21-sparse/include/asm-xeno/multicall.h
+3e5a4e67mnQfh-R8KcQCaVo2Oho6yg xenolinux-2.4.21-sparse/include/asm-xeno/page.h
+3e5a4e67uTYU5oEnIDjxuaez8njjqg xenolinux-2.4.21-sparse/include/asm-xeno/pgalloc.h
+3e5a4e67X7JyupgdYkgDX19Huj2sAw xenolinux-2.4.21-sparse/include/asm-xeno/pgtable-2level.h
+3e5a4e67gr4NLGtQ5CvSLimMYZlkOA xenolinux-2.4.21-sparse/include/asm-xeno/pgtable.h
+3e5a4e676uK4xErTBDH6XJREn9LSyg xenolinux-2.4.21-sparse/include/asm-xeno/processor.h
+3e5a4e67AJPjW-zL7p-xWuA6IVeH1g xenolinux-2.4.21-sparse/include/asm-xeno/ptrace.h
+3e5a4e68uJz-xI0IBVMD7xRLQKJDFg xenolinux-2.4.21-sparse/include/asm-xeno/segment.h
+3e5a4e68Nfdh6QcOKUTGCaYkf2LmYA xenolinux-2.4.21-sparse/include/asm-xeno/smp.h
+3e5a4e68mTr0zcp9SXDbnd-XLrrfxw xenolinux-2.4.21-sparse/include/asm-xeno/system.h
+3e5a4e68WLX3B8owTvktP3HHOtznPQ xenolinux-2.4.21-sparse/include/linux/major.h
+3e5a4e686V0nioX2ZpFf056sgvdiQw xenolinux-2.4.21-sparse/include/linux/sunrpc/debug.h
+3e5a4e68W_hpMlM3u_-QOKMp3gzcwQ xenolinux-2.4.21-sparse/init/do_mounts.c
+3e5a4e68TJJavrunYwTAnLRSBxSYqQ xenolinux-2.4.21-sparse/kernel/panic.c
+3eba8f878XjouY21EkQBXwYBsPsipQ xenolinux-2.4.21-sparse/lndir-rel
+3e6e7c1efbQe93xCvOpOVCnXTMmQ5w xenolinux-2.4.21-sparse/mkbuildtree
+3e5a4e68GxCIaFH4sy01v1wjapetaA xenolinux-2.4.21-sparse/mm/memory.c
+3e5a4e681xMPdF9xCMwpyfuYMySU5g xenolinux-2.4.21-sparse/mm/mremap.c
+3e5a4e683HKVU-sxtagrDasRB8eBVw xenolinux-2.4.21-sparse/mm/swapfile.c
+++ /dev/null
-VERSION = 2
-PATCHLEVEL = 4
-SUBLEVEL = 21
-EXTRAVERSION = -pre4-xeno
-
-KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
-
-ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/)
-
-# Xeno hack XXX
-ARCH := xeno
-SUBARCH := i386
-
-KERNELPATH=kernel-$(shell echo $(KERNELRELEASE) | sed -e "s/-//g")
-
-CONFIG_SHELL := $(shell if [ -x "$$BASH" ]; then echo $$BASH; \
- else if [ -x /bin/bash ]; then echo /bin/bash; \
- else echo sh; fi ; fi)
-TOPDIR := $(shell /bin/pwd)
-
-HPATH = $(TOPDIR)/include
-FINDHPATH = $(HPATH)/asm $(HPATH)/linux $(HPATH)/scsi $(HPATH)/net $(HPATH)/math-emu
-
-HOSTCC = gcc
-HOSTCFLAGS = -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer
-
-CROSS_COMPILE =
-
-#
-# Include the make variables (CC, etc...)
-#
-
-AS = $(CROSS_COMPILE)as
-LD = $(CROSS_COMPILE)ld
-CC = $(CROSS_COMPILE)gcc
-CPP = $(CC) -E
-AR = $(CROSS_COMPILE)ar
-NM = $(CROSS_COMPILE)nm
-STRIP = $(CROSS_COMPILE)strip
-OBJCOPY = $(CROSS_COMPILE)objcopy
-OBJDUMP = $(CROSS_COMPILE)objdump
-MAKEFILES = $(TOPDIR)/.config
-GENKSYMS = /sbin/genksyms
-DEPMOD = /sbin/depmod
-MODFLAGS = -DMODULE
-CFLAGS_KERNEL =
-PERL = perl
-
-export VERSION PATCHLEVEL SUBLEVEL EXTRAVERSION KERNELRELEASE ARCH \
- CONFIG_SHELL TOPDIR HPATH HOSTCC HOSTCFLAGS CROSS_COMPILE AS LD CC \
- CPP AR NM STRIP OBJCOPY OBJDUMP MAKE MAKEFILES GENKSYMS MODFLAGS PERL
-
-all: do-it-all
-
-#
-# Make "config" the default target if there is no configuration file or
-# "depend" the target if there is no top-level dependency information.
-#
-
-ifeq (.config,$(wildcard .config))
-include .config
-ifeq (.depend,$(wildcard .depend))
-include .depend
-do-it-all: Version vmlinux
-else
-CONFIGURATION = depend
-do-it-all: depend
-endif
-else
-CONFIGURATION = config
-do-it-all: config
-endif
-
-#
-# INSTALL_PATH specifies where to place the updated kernel and system map
-# images. Uncomment if you want to place them anywhere other than root.
-#
-
-#export INSTALL_PATH=/boot
-
-#
-# INSTALL_MOD_PATH specifies a prefix to MODLIB for module directory
-# relocations required by build roots. This is not defined in the
-# makefile but the arguement can be passed to make if needed.
-#
-
-MODLIB := $(INSTALL_MOD_PATH)/lib/modules/$(KERNELRELEASE)
-export MODLIB
-
-#
-# standard CFLAGS
-#
-
-CPPFLAGS := -D__KERNEL__ -I$(HPATH)
-
-CFLAGS := $(CPPFLAGS) -Wall -Wstrict-prototypes -Wno-trigraphs -O2 \
- -fno-strict-aliasing -fno-common
-ifndef CONFIG_FRAME_POINTER
-CFLAGS += -fomit-frame-pointer
-endif
-AFLAGS := -D__ASSEMBLY__ $(CPPFLAGS)
-
-#
-# ROOT_DEV specifies the default root-device when making the image.
-# This can be either FLOPPY, CURRENT, /dev/xxxx or empty, in which case
-# the default of FLOPPY is used by 'build'.
-# This is i386 specific.
-#
-
-export ROOT_DEV = CURRENT
-
-#
-# If you want to preset the SVGA mode, uncomment the next line and
-# set SVGA_MODE to whatever number you want.
-# Set it to -DSVGA_MODE=NORMAL_VGA if you just want the EGA/VGA mode.
-# The number is the same as you would ordinarily press at bootup.
-# This is i386 specific.
-#
-
-export SVGA_MODE = -DSVGA_MODE=NORMAL_VGA
-
-#
-# If you want the RAM disk device, define this to be the size in blocks.
-# This is i386 specific.
-#
-
-#export RAMDISK = -DRAMDISK=512
-
-CORE_FILES =kernel/kernel.o mm/mm.o fs/fs.o ipc/ipc.o
-NETWORKS =net/network.o
-
-LIBS =$(TOPDIR)/lib/lib.a
-SUBDIRS =kernel drivers mm fs net ipc lib
-
-DRIVERS-n :=
-DRIVERS-y :=
-DRIVERS-m :=
-DRIVERS- :=
-
-DRIVERS-$(CONFIG_ACPI) += drivers/acpi/acpi.o
-DRIVERS-$(CONFIG_PARPORT) += drivers/parport/driver.o
-DRIVERS-y += drivers/char/char.o \
- drivers/block/block.o \
- drivers/misc/misc.o \
- drivers/net/net.o
-DRIVERS-$(CONFIG_AGP) += drivers/char/agp/agp.o
-DRIVERS-$(CONFIG_DRM_NEW) += drivers/char/drm/drm.o
-DRIVERS-$(CONFIG_DRM_OLD) += drivers/char/drm-4.0/drm.o
-DRIVERS-$(CONFIG_NUBUS) += drivers/nubus/nubus.a
-DRIVERS-$(CONFIG_NET_FC) += drivers/net/fc/fc.o
-DRIVERS-$(CONFIG_DEV_APPLETALK) += drivers/net/appletalk/appletalk.o
-DRIVERS-$(CONFIG_TR) += drivers/net/tokenring/tr.o
-DRIVERS-$(CONFIG_WAN) += drivers/net/wan/wan.o
-DRIVERS-$(CONFIG_ARCNET) += drivers/net/arcnet/arcnetdrv.o
-DRIVERS-$(CONFIG_ATM) += drivers/atm/atm.o
-DRIVERS-$(CONFIG_IDE) += drivers/ide/idedriver.o
-DRIVERS-$(CONFIG_FC4) += drivers/fc4/fc4.a
-DRIVERS-$(CONFIG_SCSI) += drivers/scsi/scsidrv.o
-DRIVERS-$(CONFIG_FUSION_BOOT) += drivers/message/fusion/fusion.o
-DRIVERS-$(CONFIG_IEEE1394) += drivers/ieee1394/ieee1394drv.o
-
-ifneq ($(CONFIG_CD_NO_IDESCSI)$(CONFIG_BLK_DEV_IDECD)$(CONFIG_BLK_DEV_SR)$(CONFIG_PARIDE_PCD),)
-DRIVERS-y += drivers/cdrom/driver.o
-endif
-
-DRIVERS-$(CONFIG_SOUND) += drivers/sound/sounddrivers.o
-DRIVERS-$(CONFIG_PCI) += drivers/pci/driver.o
-DRIVERS-$(CONFIG_MTD) += drivers/mtd/mtdlink.o
-DRIVERS-$(CONFIG_PCMCIA) += drivers/pcmcia/pcmcia.o
-DRIVERS-$(CONFIG_NET_PCMCIA) += drivers/net/pcmcia/pcmcia_net.o
-DRIVERS-$(CONFIG_NET_WIRELESS) += drivers/net/wireless/wireless_net.o
-DRIVERS-$(CONFIG_PCMCIA_CHRDEV) += drivers/char/pcmcia/pcmcia_char.o
-DRIVERS-$(CONFIG_DIO) += drivers/dio/dio.a
-DRIVERS-$(CONFIG_SBUS) += drivers/sbus/sbus_all.o
-DRIVERS-$(CONFIG_ZORRO) += drivers/zorro/driver.o
-DRIVERS-$(CONFIG_FC4) += drivers/fc4/fc4.a
-DRIVERS-$(CONFIG_PPC32) += drivers/macintosh/macintosh.o
-DRIVERS-$(CONFIG_MAC) += drivers/macintosh/macintosh.o
-DRIVERS-$(CONFIG_ISAPNP) += drivers/pnp/pnp.o
-DRIVERS-$(CONFIG_SGI_IP22) += drivers/sgi/sgi.a
-DRIVERS-$(CONFIG_VT) += drivers/video/video.o
-DRIVERS-$(CONFIG_PARIDE) += drivers/block/paride/paride.a
-DRIVERS-$(CONFIG_HAMRADIO) += drivers/net/hamradio/hamradio.o
-DRIVERS-$(CONFIG_TC) += drivers/tc/tc.a
-DRIVERS-$(CONFIG_USB) += drivers/usb/usbdrv.o
-DRIVERS-y +=drivers/media/media.o
-DRIVERS-$(CONFIG_INPUT) += drivers/input/inputdrv.o
-DRIVERS-$(CONFIG_HIL) += drivers/hil/hil.o
-DRIVERS-$(CONFIG_I2O) += drivers/message/i2o/i2o.o
-DRIVERS-$(CONFIG_IRDA) += drivers/net/irda/irda.o
-DRIVERS-$(CONFIG_I2C) += drivers/i2c/i2c.o
-DRIVERS-$(CONFIG_PHONE) += drivers/telephony/telephony.o
-DRIVERS-$(CONFIG_MD) += drivers/md/mddev.o
-DRIVERS-$(CONFIG_GSC) += drivers/gsc/gscbus.o
-DRIVERS-$(CONFIG_BLUEZ) += drivers/bluetooth/bluetooth.o
-DRIVERS-$(CONFIG_HOTPLUG_PCI) += drivers/hotplug/vmlinux-obj.o
-DRIVERS-$(CONFIG_ISDN_BOOL) += drivers/isdn/vmlinux-obj.o
-
-DRIVERS := $(DRIVERS-y)
-
-
-# files removed with 'make clean'
-CLEAN_FILES = \
- kernel/ksyms.lst include/linux/compile.h \
- vmlinux System.map \
- .tmp* \
- drivers/char/consolemap_deftbl.c drivers/video/promcon_tbl.c \
- drivers/char/conmakehash \
- drivers/char/drm/*-mod.c \
- drivers/pci/devlist.h drivers/pci/classlist.h drivers/pci/gen-devlist \
- drivers/zorro/devlist.h drivers/zorro/gen-devlist \
- drivers/sound/bin2hex drivers/sound/hex2hex \
- drivers/atm/fore200e_mkfirm drivers/atm/{pca,sba}*{.bin,.bin1,.bin2} \
- drivers/scsi/aic7xxx/aicasm/aicasm \
- drivers/scsi/aic7xxx/aicasm/aicasm_gram.c \
- drivers/scsi/aic7xxx/aicasm/aicasm_gram.h \
- drivers/scsi/aic7xxx/aicasm/aicasm_macro_gram.c \
- drivers/scsi/aic7xxx/aicasm/aicasm_macro_gram.h \
- drivers/scsi/aic7xxx/aicasm/aicasm_macro_scan.c \
- drivers/scsi/aic7xxx/aicasm/aicasm_scan.c \
- drivers/scsi/aic7xxx/aicasm/aicdb.h \
- drivers/scsi/aic7xxx/aicasm/y.tab.h \
- drivers/scsi/53c700_d.h \
- net/khttpd/make_times_h \
- net/khttpd/times.h \
- submenu*
-# directories removed with 'make clean'
-CLEAN_DIRS = \
- modules
-
-# files removed with 'make mrproper'
-MRPROPER_FILES = \
- include/linux/autoconf.h include/linux/version.h \
- drivers/net/hamradio/soundmodem/sm_tbl_{afsk1200,afsk2666,fsk9600}.h \
- drivers/net/hamradio/soundmodem/sm_tbl_{hapn4800,psk4800}.h \
- drivers/net/hamradio/soundmodem/sm_tbl_{afsk2400_7,afsk2400_8}.h \
- drivers/net/hamradio/soundmodem/gentbl \
- drivers/sound/*_boot.h drivers/sound/.*.boot \
- drivers/sound/msndinit.c \
- drivers/sound/msndperm.c \
- drivers/sound/pndsperm.c \
- drivers/sound/pndspini.c \
- drivers/atm/fore200e_*_fw.c drivers/atm/.fore200e_*.fw \
- .version .config* config.in config.old \
- scripts/tkparse scripts/kconfig.tk scripts/kconfig.tmp \
- scripts/lxdialog/*.o scripts/lxdialog/lxdialog \
- .menuconfig.log \
- include/asm \
- .hdepend scripts/mkdep scripts/split-include scripts/docproc \
- $(TOPDIR)/include/linux/modversions.h \
- kernel.spec
-
-# directories removed with 'make mrproper'
-MRPROPER_DIRS = \
- include/config \
- $(TOPDIR)/include/linux/modules
-
-
-include arch/$(ARCH)/Makefile
-
-# Extra cflags for kbuild 2.4. The default is to forbid includes by kernel code
-# from user space headers. Some UML code requires user space headers, in the
-# UML Makefiles add 'kbuild_2_4_nostdinc :=' before include Rules.make. No
-# other kernel code should include user space headers, if you need
-# 'kbuild_2_4_nostdinc :=' or -I/usr/include for kernel code and you are not UML
-# then your code is broken! KAO.
-
-kbuild_2_4_nostdinc := -nostdinc -iwithprefix include
-export kbuild_2_4_nostdinc
-
-export CPPFLAGS CFLAGS CFLAGS_KERNEL AFLAGS AFLAGS_KERNEL
-
-export NETWORKS DRIVERS LIBS HEAD LDFLAGS LINKFLAGS MAKEBOOT ASFLAGS
-
-.S.s:
- $(CPP) $(AFLAGS) $(AFLAGS_KERNEL) -traditional -o $*.s $<
-.S.o:
- $(CC) $(AFLAGS) $(AFLAGS_KERNEL) -traditional -c -o $*.o $<
-
-Version: dummy
- @rm -f include/linux/compile.h
-
-boot: vmlinux
- @$(MAKE) CFLAGS="$(CFLAGS) $(CFLAGS_KERNEL)" -C arch/$(ARCH)/boot
-
-vmlinux: include/linux/version.h $(CONFIGURATION) init/main.o init/version.o init/do_mounts.o linuxsubdirs
- $(LD) $(LINKFLAGS) $(HEAD) init/main.o init/version.o init/do_mounts.o \
- --start-group \
- $(CORE_FILES) \
- $(DRIVERS) \
- $(NETWORKS) \
- $(LIBS) \
- --end-group \
- -o vmlinux
- $(NM) vmlinux | grep -v '\(compiled\)\|\(\.o$$\)\|\( [aUw] \)\|\(\.\.ng$$\)\|\(LASH[RL]DI\)' | sort > System.map
-
-symlinks:
- rm -f include/asm
- ( cd include ; ln -sf asm-$(ARCH) asm)
- @if [ ! -d include/linux/modules ]; then \
- mkdir include/linux/modules; \
- fi
-
-oldconfig: symlinks
- $(CONFIG_SHELL) scripts/Configure -d arch/$(ARCH)/config.in
-
-xconfig: symlinks
- $(MAKE) -C scripts kconfig.tk
- wish -f scripts/kconfig.tk
-
-menuconfig: include/linux/version.h symlinks
- $(MAKE) -C scripts/lxdialog all
- $(CONFIG_SHELL) scripts/Menuconfig arch/$(ARCH)/config.in
-
-config: symlinks
- $(CONFIG_SHELL) scripts/Configure arch/$(ARCH)/config.in
-
-include/config/MARKER: scripts/split-include include/linux/autoconf.h
- scripts/split-include include/linux/autoconf.h include/config
- @ touch include/config/MARKER
-
-linuxsubdirs: $(patsubst %, _dir_%, $(SUBDIRS))
-
-$(patsubst %, _dir_%, $(SUBDIRS)) : dummy include/linux/version.h include/config/MARKER
- $(MAKE) CFLAGS="$(CFLAGS) $(CFLAGS_KERNEL)" -C $(patsubst _dir_%, %, $@)
-
-$(TOPDIR)/include/linux/version.h: include/linux/version.h
-$(TOPDIR)/include/linux/compile.h: include/linux/compile.h
-
-newversion:
- . scripts/mkversion > .tmpversion
- @mv -f .tmpversion .version
-
-uts_len := 64
-uts_truncate := sed -e 's/\(.\{1,$(uts_len)\}\).*/\1/'
-
-include/linux/compile.h: $(CONFIGURATION) include/linux/version.h newversion
- @echo -n \#`cat .version` > .ver1
- @if [ -n "$(CONFIG_SMP)" ] ; then echo -n " SMP" >> .ver1; fi
- @if [ -f .name ]; then echo -n \-`cat .name` >> .ver1; fi
- @LANG=C echo ' '`date` >> .ver1
- @echo \#define UTS_VERSION \"`cat .ver1 | $(uts_truncate)`\" > .ver
- @LANG=C echo \#define LINUX_COMPILE_TIME \"`date +%T`\" >> .ver
- @echo \#define LINUX_COMPILE_BY \"`whoami`\" >> .ver
- @echo \#define LINUX_COMPILE_HOST \"`hostname | $(uts_truncate)`\" >> .ver
- @([ -x /bin/dnsdomainname ] && /bin/dnsdomainname > .ver1) || \
- ([ -x /bin/domainname ] && /bin/domainname > .ver1) || \
- echo > .ver1
- @echo \#define LINUX_COMPILE_DOMAIN \"`cat .ver1 | $(uts_truncate)`\" >> .ver
- @echo \#define LINUX_COMPILER \"`$(CC) $(CFLAGS) -v 2>&1 | tail -1`\" >> .ver
- @mv -f .ver $@
- @rm -f .ver1
-
-include/linux/version.h: ./Makefile
- @expr length "$(KERNELRELEASE)" \<= $(uts_len) > /dev/null || \
- (echo KERNELRELEASE \"$(KERNELRELEASE)\" exceeds $(uts_len) characters >&2; false)
- @echo \#define UTS_RELEASE \"$(KERNELRELEASE)\" > .ver
- @echo \#define LINUX_VERSION_CODE `expr $(VERSION) \\* 65536 + $(PATCHLEVEL) \\* 256 + $(SUBLEVEL)` >> .ver
- @echo '#define KERNEL_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c))' >>.ver
- @mv -f .ver $@
-
-comma := ,
-
-init/version.o: init/version.c include/linux/compile.h include/config/MARKER
- $(CC) $(CFLAGS) $(CFLAGS_KERNEL) -DUTS_MACHINE='"$(SUBARCH)"' -DKBUILD_BASENAME=$(subst $(comma),_,$(subst -,_,$(*F))) -c -o init/version.o init/version.c
-
-init/main.o: init/main.c include/config/MARKER
- $(CC) $(CFLAGS) $(CFLAGS_KERNEL) $(PROFILING) -DKBUILD_BASENAME=$(subst $(comma),_,$(subst -,_,$(*F))) -c -o $@ $<
-
-init/do_mounts.o: init/do_mounts.c include/config/MARKER
- $(CC) $(CFLAGS) $(CFLAGS_KERNEL) $(PROFILING) -DKBUILD_BASENAME=$(subst $(comma),_,$(subst -,_,$(*F))) -c -o $@ $<
-
-fs lib mm ipc kernel drivers net: dummy
- $(MAKE) CFLAGS="$(CFLAGS) $(CFLAGS_KERNEL)" $(subst $@, _dir_$@, $@)
-
-TAGS: dummy
- { find include/asm-${ARCH} -name '*.h' -print ; \
- find include -type d \( -name "asm-*" -o -name config \) -prune -o -name '*.h' -print ; \
- find $(SUBDIRS) init arch/${ARCH} -name '*.[chS]' ; } | grep -v SCCS | grep -v '\.svn' | etags -
-
-# Exuberant ctags works better with -I
-tags: dummy
- CTAGSF=`ctags --version | grep -i exuberant >/dev/null && echo "-I __initdata,__exitdata,EXPORT_SYMBOL,EXPORT_SYMBOL_NOVERS"`; \
- ctags $$CTAGSF `find include/asm-$(ARCH) -name '*.h'` && \
- find include -type d \( -name "asm-*" -o -name config \) -prune -o -name '*.h' -print | xargs ctags $$CTAGSF -a && \
- find $(SUBDIRS) init -name '*.[ch]' | xargs ctags $$CTAGSF -a
-
-ifdef CONFIG_MODULES
-ifdef CONFIG_MODVERSIONS
-MODFLAGS += -DMODVERSIONS -include $(HPATH)/linux/modversions.h
-endif
-
-.PHONY: modules
-modules: $(patsubst %, _mod_%, $(SUBDIRS))
-
-.PHONY: $(patsubst %, _mod_%, $(SUBDIRS))
-$(patsubst %, _mod_%, $(SUBDIRS)) : include/linux/version.h include/config/MARKER
- $(MAKE) -C $(patsubst _mod_%, %, $@) CFLAGS="$(CFLAGS) $(MODFLAGS)" MAKING_MODULES=1 modules
-
-.PHONY: modules_install
-modules_install: _modinst_ $(patsubst %, _modinst_%, $(SUBDIRS)) _modinst_post
-
-.PHONY: _modinst_
-_modinst_:
- @rm -rf $(MODLIB)/kernel
- @rm -f $(MODLIB)/build
- @mkdir -p $(MODLIB)/kernel
- @ln -s $(TOPDIR) $(MODLIB)/build
-
-# If System.map exists, run depmod. This deliberately does not have a
-# dependency on System.map since that would run the dependency tree on
-# vmlinux. This depmod is only for convenience to give the initial
-# boot a modules.dep even before / is mounted read-write. However the
-# boot script depmod is the master version.
-ifeq "$(strip $(INSTALL_MOD_PATH))" ""
-depmod_opts :=
-else
-depmod_opts := -b $(INSTALL_MOD_PATH) -r
-endif
-.PHONY: _modinst_post
-_modinst_post: _modinst_post_pcmcia
-# if [ -r System.map ]; then $(DEPMOD) -ae -F System.map $(depmod_opts) $(KERNELRELEASE); fi
-
-# Backwards compatibilty symlinks for people still using old versions
-# of pcmcia-cs with hard coded pathnames on insmod. Remove
-# _modinst_post_pcmcia for kernel 2.4.1.
-.PHONY: _modinst_post_pcmcia
-_modinst_post_pcmcia:
- cd $(MODLIB); \
- mkdir -p pcmcia; \
- find kernel -path '*/pcmcia/*' -name '*.o' | xargs -i -r ln -sf ../{} pcmcia
-
-.PHONY: $(patsubst %, _modinst_%, $(SUBDIRS))
-$(patsubst %, _modinst_%, $(SUBDIRS)) :
- $(MAKE) -C $(patsubst _modinst_%, %, $@) modules_install
-
-# modules disabled....
-
-else
-modules modules_install: dummy
- @echo
- @echo "The present kernel configuration has modules disabled."
- @echo "Type 'make config' and enable loadable module support."
- @echo "Then build a kernel with module support enabled."
- @echo
- @exit 1
-endif
-
-clean: archclean
- find . \( -name '*.[oas]' -o -name core -o -name '.*.flags' \) -type f -print \
- | grep -v lxdialog/ | xargs rm -f
- rm -f $(CLEAN_FILES)
- rm -rf $(CLEAN_DIRS)
- $(MAKE) -C Documentation/DocBook clean
-
-mrproper: clean archmrproper
- find . \( -size 0 -o -name .depend \) -type f -print | xargs rm -f
- rm -f $(MRPROPER_FILES)
- rm -rf $(MRPROPER_DIRS)
- $(MAKE) -C Documentation/DocBook mrproper
-
-distclean: mrproper
- rm -f core `find . \( -not -type d \) -and \
- \( -name '*.orig' -o -name '*.rej' -o -name '*~' \
- -o -name '*.bak' -o -name '#*#' -o -name '.*.orig' \
- -o -name '.*.rej' -o -name '.SUMS' -o -size 0 \) -type f -print` TAGS tags
-
-backup: mrproper
- cd .. && tar cf - linux/ | gzip -9 > backup.gz
- sync
-
-sgmldocs:
- chmod 755 $(TOPDIR)/scripts/docgen
- chmod 755 $(TOPDIR)/scripts/gen-all-syms
- chmod 755 $(TOPDIR)/scripts/kernel-doc
- $(MAKE) -C $(TOPDIR)/Documentation/DocBook books
-
-psdocs: sgmldocs
- $(MAKE) -C Documentation/DocBook ps
-
-pdfdocs: sgmldocs
- $(MAKE) -C Documentation/DocBook pdf
-
-htmldocs: sgmldocs
- $(MAKE) -C Documentation/DocBook html
-
-mandocs:
- chmod 755 $(TOPDIR)/scripts/kernel-doc
- chmod 755 $(TOPDIR)/scripts/split-man
- $(MAKE) -C Documentation/DocBook man
-
-sums:
- find . -type f -print | sort | xargs sum > .SUMS
-
-dep-files: scripts/mkdep archdep include/linux/version.h
- scripts/mkdep -- init/*.c > .depend
- scripts/mkdep -- `find $(FINDHPATH) \( -name SCCS -o -name .svn \) -prune -o -follow -name \*.h ! -name modversions.h -print` > .hdepend
- $(MAKE) $(patsubst %,_sfdep_%,$(SUBDIRS)) _FASTDEP_ALL_SUB_DIRS="$(SUBDIRS)"
-ifdef CONFIG_MODVERSIONS
- $(MAKE) update-modverfile
-endif
-
-ifdef CONFIG_MODVERSIONS
-MODVERFILE := $(TOPDIR)/include/linux/modversions.h
-else
-MODVERFILE :=
-endif
-export MODVERFILE
-
-depend dep: dep-files
-
-checkconfig:
- find * -name '*.[hcS]' -type f -print | sort | xargs $(PERL) -w scripts/checkconfig.pl
-
-checkhelp:
- find * -name [cC]onfig.in -print | sort | xargs $(PERL) -w scripts/checkhelp.pl
-
-checkincludes:
- find * -name '*.[hcS]' -type f -print | sort | xargs $(PERL) -w scripts/checkincludes.pl
-
-ifdef CONFIGURATION
-..$(CONFIGURATION):
- @echo
- @echo "You have a bad or nonexistent" .$(CONFIGURATION) ": running 'make" $(CONFIGURATION)"'"
- @echo
- $(MAKE) $(CONFIGURATION)
- @echo
- @echo "Successful. Try re-making (ignore the error that follows)"
- @echo
- exit 1
-
-#dummy: ..$(CONFIGURATION)
-dummy:
-
-else
-
-dummy:
-
-endif
-
-include Rules.make
-
-#
-# This generates dependencies for the .h files.
-#
-
-scripts/mkdep: scripts/mkdep.c
- $(HOSTCC) $(HOSTCFLAGS) -o scripts/mkdep scripts/mkdep.c
-
-scripts/split-include: scripts/split-include.c
- $(HOSTCC) $(HOSTCFLAGS) -o scripts/split-include scripts/split-include.c
-
-#
-# RPM target
-#
-# If you do a make spec before packing the tarball you can rpm -ta it
-#
-spec:
- . scripts/mkspec >kernel.spec
-
-#
-# Build a tar ball, generate an rpm from it and pack the result
-# There arw two bits of magic here
-# 1) The use of /. to avoid tar packing just the symlink
-# 2) Removing the .dep files as they have source paths in them that
-# will become invalid
-#
-rpm: clean spec
- find . \( -size 0 -o -name .depend -o -name .hdepend \) -type f -print | xargs rm -f
- set -e; \
- cd $(TOPDIR)/.. ; \
- ln -sf $(TOPDIR) $(KERNELPATH) ; \
- tar -cvz --exclude CVS -f $(KERNELPATH).tar.gz $(KERNELPATH)/. ; \
- rm $(KERNELPATH) ; \
- cd $(TOPDIR) ; \
- . scripts/mkversion > .version ; \
- rpm -ta $(TOPDIR)/../$(KERNELPATH).tar.gz ; \
- rm $(TOPDIR)/../$(KERNELPATH).tar.gz
+++ /dev/null
-#
-# xeno/Makefile
-#
-# This file is included by the global makefile so that you can add your own
-# architecture-specific flags and dependencies. Remember to do have actions
-# for "archclean" and "archdep" for cleaning up and making dependencies for
-# this architecture
-#
-# This file is subject to the terms and conditions of the GNU General Public
-# License. See the file "COPYING" in the main directory of this archive
-# for more details.
-#
-# Copyright (C) 1994 by Linus Torvalds
-#
-# 19990713 Artur Skawina <skawina@geocities.com>
-# Added '-march' and '-mpreferred-stack-boundary' support
-#
-
-LD=$(CROSS_COMPILE)ld -m elf_i386
-OBJCOPY=$(CROSS_COMPILE)objcopy -O binary -R .note -R .comment -S
-LDFLAGS=-e stext
-LINKFLAGS =-T $(TOPDIR)/arch/xeno/vmlinux.lds $(LDFLAGS)
-
-CFLAGS += -pipe
-
-# prevent gcc from keeping the stack 16 byte aligned
-CFLAGS += $(shell if $(CC) -mpreferred-stack-boundary=2 -S -o /dev/null -xc /dev/null >/dev/null 2>&1; then echo "-mpreferred-stack-boundary=2"; fi)
-
-ifdef CONFIG_M686
-CFLAGS += -march=i686
-endif
-
-ifdef CONFIG_MPENTIUMIII
-CFLAGS += -march=i686
-endif
-
-ifdef CONFIG_MPENTIUM4
-CFLAGS += -march=i686
-endif
-
-ifdef CONFIG_MK7
-CFLAGS += $(shell if $(CC) -march=athlon -S -o /dev/null -xc /dev/null >/dev/null 2>&1; then echo "-march=athlon"; else echo "-march=i686 -malign-functions=4"; fi)
-endif
-
-HEAD := arch/xeno/kernel/head.o arch/xeno/kernel/init_task.o
-
-SUBDIRS += arch/xeno/kernel arch/xeno/mm arch/xeno/lib
-SUBDIRS += arch/xeno/drivers/console arch/xeno/drivers/network
-SUBDIRS += arch/xeno/drivers/dom0 arch/xeno/drivers/block
-SUBDIRS += arch/xeno/drivers/balloon
-
-CORE_FILES += arch/xeno/kernel/kernel.o arch/xeno/mm/mm.o
-CORE_FILES += arch/xeno/drivers/console/con.o
-CORE_FILES += arch/xeno/drivers/block/blk.o
-CORE_FILES += arch/xeno/drivers/network/net.o
-CORE_FILES += arch/xeno/drivers/dom0/dom0.o
-CORE_FILES += arch/xeno/drivers/balloon/balloon_driver.o
-LIBS := $(TOPDIR)/arch/xeno/lib/lib.a $(LIBS) $(TOPDIR)/arch/xeno/lib/lib.a
-
-arch/xeno/kernel: dummy
- $(MAKE) linuxsubdirs SUBDIRS=arch/xeno/kernel
-
-arch/xeno/mm: dummy
- $(MAKE) linuxsubdirs SUBDIRS=arch/xeno/mm
-
-arch/xeno/drivers/console: dummy
- $(MAKE) linuxsubdirs SUBDIRS=arch/xeno/drivers/console
-
-arch/xeno/drivers/network: dummy
- $(MAKE) linuxsubdirs SUBDIRS=arch/xeno/drivers/network
-
-arch/xeno/drivers/block: dummy
- $(MAKE) linuxsubdirs SUBDIRS=arch/xeno/drivers/block
-
-arch/xeno/drivers/dom0: dummy
- $(MAKE) linuxsubdirs SUBDIRS=arch/xeno/drivers/dom0
-
-arch/xeno/drivers/balloon: dummy
- $(MAKE) linuxsubdirs SUBDIRS=arch/xeno/drivers/balloon
-
-MAKEBOOT = $(MAKE) -C arch/$(ARCH)/boot
-
-vmlinux: arch/xeno/vmlinux.lds
-
-FORCE: ;
-
-.PHONY: bzImage compressed clean archclean archmrproper archdep
-
-bzImage: vmlinux
- @$(MAKEBOOT) image.gz
-
-install: bzImage
- cp -a arch/$(ARCH)/boot/image.gz ../install/boot/xenolinux.gz
-
-archclean:
- @$(MAKEBOOT) clean
-
-archmrproper:
-
-archdep:
- @$(MAKEBOOT) dep
+++ /dev/null
-#
-# arch/xeno/boot/Makefile
-#
-
-image.gz: image
- gzip -f -9 < $< > $@
-
-image: $(TOPDIR)/vmlinux
- # Guest OS header -- first 8 bytes are identifier 'XenoGues'.
- echo -e -n 'XenoGues' >$@
- # Guest OS header -- next 4 bytes are load address (0xC0000000).
- echo -e -n '\000\000\000\300' >>$@
- $(OBJCOPY) $< image.body
- # Guest OS header is immediately followed by raw OS image.
- # Start address must be at byte 0.
- cat image.body >>$@
- rm -f image.body
-
-dep:
-
-clean:
- rm -f image image.gz
+++ /dev/null
-#
-# For a description of the syntax of this configuration file,
-# see Documentation/kbuild/config-language.txt.
-#
-mainmenu_name "Linux Kernel Configuration"
-
-define_bool CONFIG_XENO y
-
-define_bool CONFIG_X86 y
-define_bool CONFIG_ISA y
-define_bool CONFIG_SBUS n
-
-define_bool CONFIG_UID16 y
-
-mainmenu_option next_comment
-comment 'Code maturity level options'
-bool 'Prompt for development and/or incomplete code/drivers' CONFIG_EXPERIMENTAL
-endmenu
-
-mainmenu_option next_comment
-comment 'Loadable module support'
-bool 'Enable loadable module support' CONFIG_MODULES
-if [ "$CONFIG_MODULES" = "y" ]; then
- bool ' Set version information on all module symbols' CONFIG_MODVERSIONS
- bool ' Kernel module loader' CONFIG_KMOD
-fi
-endmenu
-
-mainmenu_option next_comment
-comment 'Processor type and features'
-choice 'Processor family' \
- "Pentium-Pro/Celeron/Pentium-II CONFIG_M686 \
- Pentium-III/Celeron(Coppermine) CONFIG_MPENTIUMIII \
- Pentium-4 CONFIG_MPENTIUM4 \
- Athlon/Duron/K7 CONFIG_MK7" Pentium-Pro
-
- define_bool CONFIG_X86_WP_WORKS_OK y
- define_bool CONFIG_X86_INVLPG y
- define_bool CONFIG_X86_CMPXCHG y
- define_bool CONFIG_X86_XADD y
- define_bool CONFIG_X86_BSWAP y
- define_bool CONFIG_X86_POPAD_OK y
- define_bool CONFIG_RWSEM_GENERIC_SPINLOCK n
- define_bool CONFIG_RWSEM_XCHGADD_ALGORITHM y
-
- define_bool CONFIG_X86_GOOD_APIC y
- define_bool CONFIG_X86_PGE y
- define_bool CONFIG_X86_USE_PPRO_CHECKSUM y
- define_bool CONFIG_X86_TSC y
-
-if [ "$CONFIG_M686" = "y" ]; then
- define_int CONFIG_X86_L1_CACHE_SHIFT 5
-fi
-if [ "$CONFIG_MPENTIUMIII" = "y" ]; then
- define_int CONFIG_X86_L1_CACHE_SHIFT 5
-fi
-if [ "$CONFIG_MPENTIUM4" = "y" ]; then
- define_int CONFIG_X86_L1_CACHE_SHIFT 7
-fi
-if [ "$CONFIG_MK7" = "y" ]; then
- define_int CONFIG_X86_L1_CACHE_SHIFT 6
- define_bool CONFIG_X86_USE_3DNOW y
-fi
-
-choice 'High Memory Support' \
- "off CONFIG_NOHIGHMEM \
- 4GB CONFIG_HIGHMEM4G \
- 64GB CONFIG_HIGHMEM64G" off
-if [ "$CONFIG_HIGHMEM4G" = "y" ]; then
- define_bool CONFIG_HIGHMEM y
-fi
-if [ "$CONFIG_HIGHMEM64G" = "y" ]; then
- define_bool CONFIG_HIGHMEM y
- define_bool CONFIG_X86_PAE y
-fi
-
-#bool 'Symmetric multi-processing support' CONFIG_SMP
-#if [ "$CONFIG_SMP" = "y" -a "$CONFIG_X86_CMPXCHG" = "y" ]; then
-# define_bool CONFIG_HAVE_DEC_LOCK y
-#fi
-endmenu
-
-mainmenu_option next_comment
-comment 'General setup'
-
-bool 'Networking support' CONFIG_NET
-
-bool 'System V IPC' CONFIG_SYSVIPC
-bool 'BSD Process Accounting' CONFIG_BSD_PROCESS_ACCT
-bool 'Sysctl support' CONFIG_SYSCTL
-if [ "$CONFIG_PROC_FS" = "y" ]; then
- choice 'Kernel core (/proc/kcore) format' \
- "ELF CONFIG_KCORE_ELF \
- A.OUT CONFIG_KCORE_AOUT" ELF
-fi
-tristate 'Kernel support for a.out binaries' CONFIG_BINFMT_AOUT
-tristate 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF
-tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC
-
-endmenu
-
-if [ "$CONFIG_NET" = "y" ]; then
- source net/Config.in
-fi
-
-
-#
-# Block device driver configuration
-#
-mainmenu_option next_comment
-comment 'Block devices'
-tristate 'Loopback device support' CONFIG_BLK_DEV_LOOP
-dep_tristate 'Network block device support' CONFIG_BLK_DEV_NBD $CONFIG_NET
-tristate 'RAM disk support' CONFIG_BLK_DEV_RAM
-if [ "$CONFIG_BLK_DEV_RAM" = "y" -o "$CONFIG_BLK_DEV_RAM" = "m" ]; then
- int ' Default RAM disk size' CONFIG_BLK_DEV_RAM_SIZE 4096
-fi
-dep_bool ' Initial RAM disk (initrd) support' CONFIG_BLK_DEV_INITRD $CONFIG_BLK_DEV_RAM
-bool 'Per partition statistics in /proc/partitions' CONFIG_BLK_STATS
-bool 'XenoLinux virtual block device support' CONFIG_XENOLINUX_BLOCK
-endmenu
-define_bool CONFIG_BLK_DEV_IDE_MODES n
-define_bool CONFIG_BLK_DEV_HD n
-
-
-mainmenu_option next_comment
-comment 'Character devices'
-
-bool 'Xen console support' CONFIG_XEN_CONSOLE
-comment 'The options below are alpha-stage and will probably not work'
-bool 'Virtual terminal' CONFIG_VT
-if [ "$CONFIG_VT" = "y" ]; then
- bool ' Support for console on virtual terminal' CONFIG_VT_CONSOLE
- bool ' Support for VGA Video' CONFIG_VGA_CONSOLE
- bool ' Support for Dummy Video (for testing)' CONFIG_DUMMY_CONSOLE
- bool ' PS/2 mouse (aka "auxiliary device") support' CONFIG_PSMOUSE
-fi
-
-bool 'Unix98 PTY support' CONFIG_UNIX98_PTYS
-if [ "$CONFIG_UNIX98_PTYS" = "y" ]; then
- int 'Maximum number of Unix98 PTYs in use (0-2048)' CONFIG_UNIX98_PTY_COUNT 256
-fi
-
-endmenu
-
-source fs/Config.in
-
-mainmenu_option next_comment
-comment 'Kernel hacking'
-
-bool 'Kernel debugging' CONFIG_DEBUG_KERNEL
-if [ "$CONFIG_DEBUG_KERNEL" != "n" ]; then
- bool ' Debug high memory support' CONFIG_DEBUG_HIGHMEM
- bool ' Debug memory allocations' CONFIG_DEBUG_SLAB
- bool ' Memory mapped I/O debugging' CONFIG_DEBUG_IOVIRT
- bool ' Magic SysRq key' CONFIG_MAGIC_SYSRQ
- bool ' Spinlock debugging' CONFIG_DEBUG_SPINLOCK
- bool ' Verbose BUG() reporting (adds 70K)' CONFIG_DEBUG_BUGVERBOSE
- bool ' Load all symbols for debugging' CONFIG_KALLSYMS
- bool ' Compile the kernel with frame pointers' CONFIG_FRAME_POINTER
-fi
-
-endmenu
-
-source lib/Config.in
+++ /dev/null
-#
-# Automatically generated make config: don't edit
-#
-CONFIG_XENO=y
-CONFIG_X86=y
-CONFIG_ISA=y
-# CONFIG_SBUS is not set
-CONFIG_UID16=y
-
-#
-# Code maturity level options
-#
-# CONFIG_EXPERIMENTAL is not set
-
-#
-# Loadable module support
-#
-CONFIG_MODULES=y
-CONFIG_MODVERSIONS=y
-CONFIG_KMOD=y
-
-#
-# Processor type and features
-#
-CONFIG_M686=y
-# CONFIG_MPENTIUMIII is not set
-# CONFIG_MPENTIUM4 is not set
-# CONFIG_MK7 is not set
-CONFIG_X86_WP_WORKS_OK=y
-CONFIG_X86_INVLPG=y
-CONFIG_X86_CMPXCHG=y
-CONFIG_X86_XADD=y
-CONFIG_X86_BSWAP=y
-CONFIG_X86_POPAD_OK=y
-# CONFIG_RWSEM_GENERIC_SPINLOCK is not set
-CONFIG_RWSEM_XCHGADD_ALGORITHM=y
-CONFIG_X86_GOOD_APIC=y
-CONFIG_X86_PGE=y
-CONFIG_X86_USE_PPRO_CHECKSUM=y
-CONFIG_X86_TSC=y
-CONFIG_X86_L1_CACHE_SHIFT=5
-CONFIG_NOHIGHMEM=y
-# CONFIG_HIGHMEM4G is not set
-# CONFIG_HIGHMEM64G is not set
-
-#
-# General setup
-#
-CONFIG_NET=y
-CONFIG_SYSVIPC=y
-# CONFIG_BSD_PROCESS_ACCT is not set
-CONFIG_SYSCTL=y
-CONFIG_KCORE_ELF=y
-# CONFIG_KCORE_AOUT is not set
-CONFIG_BINFMT_AOUT=y
-CONFIG_BINFMT_ELF=y
-# CONFIG_BINFMT_MISC is not set
-
-#
-# Networking options
-#
-CONFIG_PACKET=y
-CONFIG_PACKET_MMAP=y
-# CONFIG_NETLINK_DEV is not set
-# CONFIG_NETFILTER is not set
-CONFIG_FILTER=y
-CONFIG_UNIX=y
-CONFIG_INET=y
-# CONFIG_IP_MULTICAST is not set
-# CONFIG_IP_ADVANCED_ROUTER is not set
-CONFIG_IP_PNP=y
-# CONFIG_IP_PNP_DHCP is not set
-# CONFIG_IP_PNP_BOOTP is not set
-# CONFIG_IP_PNP_RARP is not set
-# CONFIG_NET_IPIP is not set
-# CONFIG_NET_IPGRE is not set
-# CONFIG_INET_ECN is not set
-# CONFIG_SYN_COOKIES is not set
-# CONFIG_VLAN_8021Q is not set
-
-#
-#
-#
-# CONFIG_IPX is not set
-# CONFIG_ATALK is not set
-
-#
-# Appletalk devices
-#
-# CONFIG_DEV_APPLETALK is not set
-# CONFIG_DECNET is not set
-# CONFIG_BRIDGE is not set
-
-#
-# QoS and/or fair queueing
-#
-# CONFIG_NET_SCHED is not set
-
-#
-# Network testing
-#
-# CONFIG_NET_PKTGEN is not set
-
-#
-# Block devices
-#
-# CONFIG_BLK_DEV_FD is not set
-# CONFIG_BLK_DEV_XD is not set
-# CONFIG_PARIDE is not set
-# CONFIG_BLK_CPQ_DA is not set
-# CONFIG_BLK_CPQ_CISS_DA is not set
-# CONFIG_CISS_SCSI_TAPE is not set
-# CONFIG_BLK_DEV_DAC960 is not set
-# CONFIG_BLK_DEV_UMEM is not set
-CONFIG_BLK_DEV_LOOP=y
-CONFIG_BLK_DEV_NBD=y
-CONFIG_BLK_DEV_RAM=y
-CONFIG_BLK_DEV_RAM_SIZE=4096
-CONFIG_BLK_DEV_INITRD=y
-# CONFIG_BLK_STATS is not set
-CONFIG_XENOLINUX_BLOCK=y
-# CONFIG_BLK_DEV_IDE_MODES is not set
-# CONFIG_BLK_DEV_HD is not set
-
-#
-# Character devices
-#
-CONFIG_XEN_CONSOLE=y
-# CONFIG_VT is not set
-# CONFIG_VGA_CONSOLE is not set
-# CONFIG_DUMMY_CONSOLE is not set
-# CONFIG_PSMOUSE is not set
-# CONFIG_UNIX98_PTYS is not set
-
-#
-# File systems
-#
-# CONFIG_QUOTA is not set
-CONFIG_AUTOFS_FS=y
-CONFIG_AUTOFS4_FS=y
-# CONFIG_REISERFS_FS is not set
-# CONFIG_REISERFS_CHECK is not set
-# CONFIG_REISERFS_PROC_INFO is not set
-# CONFIG_ADFS_FS is not set
-# CONFIG_ADFS_FS_RW is not set
-# CONFIG_AFFS_FS is not set
-# CONFIG_HFS_FS is not set
-# CONFIG_BEFS_FS is not set
-# CONFIG_BEFS_DEBUG is not set
-# CONFIG_BFS_FS is not set
-CONFIG_EXT3_FS=y
-CONFIG_JBD=y
-# CONFIG_JBD_DEBUG is not set
-# CONFIG_FAT_FS is not set
-# CONFIG_MSDOS_FS is not set
-# CONFIG_UMSDOS_FS is not set
-# CONFIG_VFAT_FS is not set
-# CONFIG_EFS_FS is not set
-# CONFIG_JFFS_FS is not set
-# CONFIG_JFFS2_FS is not set
-# CONFIG_CRAMFS is not set
-CONFIG_TMPFS=y
-CONFIG_RAMFS=y
-CONFIG_ISO9660_FS=y
-CONFIG_JOLIET=y
-CONFIG_ZISOFS=y
-# CONFIG_JFS_FS is not set
-# CONFIG_JFS_DEBUG is not set
-# CONFIG_JFS_STATISTICS is not set
-# CONFIG_MINIX_FS is not set
-# CONFIG_VXFS_FS is not set
-# CONFIG_NTFS_FS is not set
-# CONFIG_NTFS_RW is not set
-# CONFIG_HPFS_FS is not set
-CONFIG_PROC_FS=y
-# CONFIG_DEVFS_FS is not set
-# CONFIG_DEVFS_MOUNT is not set
-# CONFIG_DEVFS_DEBUG is not set
-# CONFIG_DEVPTS_FS is not set
-# CONFIG_QNX4FS_FS is not set
-# CONFIG_QNX4FS_RW is not set
-# CONFIG_ROMFS_FS is not set
-CONFIG_EXT2_FS=y
-# CONFIG_SYSV_FS is not set
-# CONFIG_UDF_FS is not set
-# CONFIG_UDF_RW is not set
-# CONFIG_UFS_FS is not set
-# CONFIG_UFS_FS_WRITE is not set
-
-#
-# Network File Systems
-#
-# CONFIG_CODA_FS is not set
-# CONFIG_INTERMEZZO_FS is not set
-CONFIG_NFS_FS=y
-CONFIG_NFS_V3=y
-CONFIG_ROOT_NFS=y
-CONFIG_NFSD=y
-CONFIG_NFSD_V3=y
-# CONFIG_NFSD_TCP is not set
-CONFIG_SUNRPC=y
-CONFIG_LOCKD=y
-CONFIG_LOCKD_V4=y
-# CONFIG_SMB_FS is not set
-# CONFIG_NCP_FS is not set
-# CONFIG_NCPFS_PACKET_SIGNING is not set
-# CONFIG_NCPFS_IOCTL_LOCKING is not set
-# CONFIG_NCPFS_STRONG is not set
-# CONFIG_NCPFS_NFS_NS is not set
-# CONFIG_NCPFS_OS2_NS is not set
-# CONFIG_NCPFS_SMALLDOS is not set
-# CONFIG_NCPFS_NLS is not set
-# CONFIG_NCPFS_EXTRAS is not set
-CONFIG_ZISOFS_FS=y
-
-#
-# Partition Types
-#
-# CONFIG_PARTITION_ADVANCED is not set
-CONFIG_MSDOS_PARTITION=y
-# CONFIG_SMB_NLS is not set
-CONFIG_NLS=y
-
-#
-# Native Language Support
-#
-CONFIG_NLS_DEFAULT="iso8559-1"
-# CONFIG_NLS_CODEPAGE_437 is not set
-# CONFIG_NLS_CODEPAGE_737 is not set
-# CONFIG_NLS_CODEPAGE_775 is not set
-# CONFIG_NLS_CODEPAGE_850 is not set
-# CONFIG_NLS_CODEPAGE_852 is not set
-# CONFIG_NLS_CODEPAGE_855 is not set
-# CONFIG_NLS_CODEPAGE_857 is not set
-# CONFIG_NLS_CODEPAGE_860 is not set
-# CONFIG_NLS_CODEPAGE_861 is not set
-# CONFIG_NLS_CODEPAGE_862 is not set
-# CONFIG_NLS_CODEPAGE_863 is not set
-# CONFIG_NLS_CODEPAGE_864 is not set
-# CONFIG_NLS_CODEPAGE_865 is not set
-# CONFIG_NLS_CODEPAGE_866 is not set
-# CONFIG_NLS_CODEPAGE_869 is not set
-# CONFIG_NLS_CODEPAGE_936 is not set
-# CONFIG_NLS_CODEPAGE_950 is not set
-# CONFIG_NLS_CODEPAGE_932 is not set
-# CONFIG_NLS_CODEPAGE_949 is not set
-# CONFIG_NLS_CODEPAGE_874 is not set
-# CONFIG_NLS_ISO8859_8 is not set
-# CONFIG_NLS_CODEPAGE_1250 is not set
-# CONFIG_NLS_CODEPAGE_1251 is not set
-CONFIG_NLS_ISO8859_1=y
-# CONFIG_NLS_ISO8859_2 is not set
-# CONFIG_NLS_ISO8859_3 is not set
-# CONFIG_NLS_ISO8859_4 is not set
-# CONFIG_NLS_ISO8859_5 is not set
-# CONFIG_NLS_ISO8859_6 is not set
-# CONFIG_NLS_ISO8859_7 is not set
-# CONFIG_NLS_ISO8859_9 is not set
-# CONFIG_NLS_ISO8859_13 is not set
-# CONFIG_NLS_ISO8859_14 is not set
-# CONFIG_NLS_ISO8859_15 is not set
-# CONFIG_NLS_KOI8_R is not set
-# CONFIG_NLS_KOI8_U is not set
-# CONFIG_NLS_UTF8 is not set
-
-#
-# Kernel hacking
-#
-CONFIG_DEBUG_KERNEL=y
-# CONFIG_DEBUG_HIGHMEM is not set
-# CONFIG_DEBUG_SLAB is not set
-# CONFIG_DEBUG_IOVIRT is not set
-# CONFIG_MAGIC_SYSRQ is not set
-# CONFIG_DEBUG_SPINLOCK is not set
-# CONFIG_DEBUG_BUGVERBOSE is not set
-CONFIG_KALLSYMS=y
-# CONFIG_FRAME_POINTER is not set
-
-#
-# Library routines
-#
-CONFIG_ZLIB_INFLATE=y
-# CONFIG_ZLIB_DEFLATE is not set
+++ /dev/null
-O_TARGET := balloon_driver.o
-obj-y := balloon.o
-include $(TOPDIR)/Rules.make
+++ /dev/null
-/******************************************************************************
- * balloon.c
- *
- * Xeno balloon driver - enables returning/claiming memory to/from xen
- *
- * Copyright (c) 2003, B Dragovic
- */
-
-#include <linux/config.h>
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/errno.h>
-#include <linux/proc_fs.h>
-
-#include <linux/mm.h>
-#include <linux/mman.h>
-#include <linux/smp_lock.h>
-#include <linux/pagemap.h>
-
-#include <asm/hypervisor.h>
-#include <asm/pgalloc.h>
-#include <asm/pgtable.h>
-#include <asm/uaccess.h>
-#include <asm/tlb.h>
-
-#include "dom_mem_ops.h"
-
-/* USER DEFINES -- THESE SHOULD BE COPIED TO USER-SPACE TOOLS */
-#define USER_INFLATE_BALLOON 1 /* return mem to hypervisor */
-#define USER_DEFLATE_BALLOON 2 /* claim mem from hypervisor */
-typedef struct user_balloon_op {
- unsigned int op;
- unsigned long size;
-} user_balloon_op_t;
-/* END OF USER DEFINE */
-
-/* Dead entry written into ballon-owned entries in the PMT. */
-#define DEAD 0xdeadbeef
-
-#define BALLOON_ENTRY "balloon"
-extern struct proc_dir_entry *xeno_base;
-
-static struct proc_dir_entry *balloon_pde;
-unsigned long credit;
-
-static inline unsigned long get_ppte(unsigned long addr)
-{
- unsigned long ppte;
- pgd_t *pgd; pmd_t *pmd; pte_t *ptep;
- pgd = pgd_offset_k(addr);
-
- if ( pgd_none(*pgd) || pgd_bad(*pgd) ) BUG();
-
- pmd = pmd_offset(pgd, addr);
- if ( pmd_none(*pmd) || pmd_bad(*pmd) ) BUG();
-
- ptep = pte_offset(pmd, addr);
- ppte = (unsigned long)__pa(ptep);
-
- return ppte;
-}
-
-/* main function for relinquishing bit of memory */
-static unsigned long inflate_balloon(unsigned long num_pages)
-{
- dom_mem_op_t dom_mem_op;
- unsigned long *parray;
- unsigned long *currp;
- unsigned long curraddr;
- unsigned long ret = 0;
- unsigned long vaddr;
- unsigned long i, j;
-
- parray = (unsigned long *)kmalloc(num_pages *
- sizeof(unsigned long), GFP_KERNEL);
- currp = parray;
-
- for ( i = 0; i < num_pages; i++ )
- {
- /* try to obtain a free page, has to be done with GFP_ATOMIC
- * as we do not want to sleep indefinately.
- */
- vaddr = __get_free_page(GFP_ATOMIC);
-
- /* if allocation fails, free all reserved pages */
- if(!vaddr){
- printk("Unable to inflate balloon by %ld, only %ld pages free.",
- num_pages, i);
- currp = parray;
- for(j = 0; j < i; j++){
- free_page(*currp++);
- }
- goto cleanup;
- }
-
- *currp++ = vaddr;
- }
-
-
- currp = parray;
- for ( i = 0; i < num_pages; i++ )
- {
- curraddr = *currp;
- *currp = virt_to_machine(*currp) >> PAGE_SHIFT;
- queue_l1_entry_update(get_ppte(curraddr) | PGREQ_NORMAL, 0);
- phys_to_machine_mapping[__pa(curraddr) >> PAGE_SHIFT] = DEAD;
- currp++;
- }
-
- XENO_flush_page_update_queue();
-
- dom_mem_op.op = BALLOON_INFLATE_OP;
- dom_mem_op.u.balloon_inflate.size = num_pages;
- dom_mem_op.u.balloon_inflate.pages = parray;
- if ( (ret = HYPERVISOR_dom_mem_op(&dom_mem_op)) != num_pages )
- {
- printk("Unable to inflate balloon, error %lx\n", ret);
- goto cleanup;
- }
-
- credit += num_pages;
- ret = num_pages;
-
- cleanup:
- kfree(parray);
-
- return ret;
-}
-
-/* install new mem pages obtained by deflate_balloon. function walks
- * phys->machine mapping table looking for DEAD entries and populates
- * them.
- */
-static unsigned long process_new_pages(unsigned long * parray,
- unsigned long num)
-{
- /* currently, this function is rather simplistic as
- * it is assumed that domain reclaims only number of
- * pages previously released. this is to change soon
- * and the code to extend page tables etc. will be
- * incorporated here.
- */
-
- unsigned long tot_pages = start_info.nr_pages;
- unsigned long * curr = parray;
- unsigned long num_installed;
- unsigned long i;
-
- num_installed = 0;
- for ( i = 0; (i < tot_pages) && (num_installed < num); i++ )
- {
- if ( phys_to_machine_mapping[i] == DEAD )
- {
- printk(KERN_ALERT "bd240 debug: proc_new_pages: i %lx, mpt %lx, %lx\n", i, i << PAGE_SHIFT, get_ppte((unsigned long)__va(i << PAGE_SHIFT)) | PGREQ_NORMAL);
- phys_to_machine_mapping[i] = *curr;
- queue_l1_entry_update((i << PAGE_SHIFT) | PGREQ_MPT_UPDATE, i);
- queue_l1_entry_update(
- get_ppte((unsigned long)__va(i << PAGE_SHIFT)) | PGREQ_NORMAL,
- ((*curr) << PAGE_SHIFT) | L1_PROT);
-
- *curr = (unsigned long)__va(i << PAGE_SHIFT);
- curr++;
- num_installed++;
- }
- }
-
- /* now, this is tricky (and will also change for machine addrs that
- * are mapped to not previously released addresses). we free pages
- * that were allocated by get_free_page (the mappings are different
- * now, of course).
- */
- curr = parray;
- for ( i = 0; i < num_installed; i++ )
- {
- free_page(*curr);
- curr++;
- }
-
- return num_installed;
-}
-
-unsigned long deflate_balloon(unsigned long num_pages)
-{
- dom_mem_op_t dom_mem_op;
- unsigned long ret;
- unsigned long * parray;
-
- printk(KERN_ALERT "bd240 debug: deflate balloon called for %lx pages\n", num_pages);
-
- if ( num_pages > credit )
- {
- printk("Can not allocate more pages than previously released.\n");
- return -EAGAIN;
- }
-
- parray = (unsigned long *)kmalloc(num_pages * sizeof(unsigned long),
- GFP_KERNEL);
-
- dom_mem_op.op = BALLOON_DEFLATE_OP;
- dom_mem_op.u.balloon_deflate.size = num_pages;
- dom_mem_op.u.balloon_deflate.pages = parray;
- if((ret = HYPERVISOR_dom_mem_op(&dom_mem_op)) != num_pages){
- printk("Unable to deflate balloon, error %lx\n", ret);
- goto cleanup;
- }
-
- if((ret = process_new_pages(parray, num_pages)) < num_pages){
- printk("Unable to deflate balloon by specified %lx pages, only %lx.\n",
- num_pages, ret);
- goto cleanup;
- }
-
- ret = num_pages;
- credit -= num_pages;
-
- cleanup:
- kfree(parray);
-
- return ret;
-}
-
-static int balloon_write(struct file *file, const char *buffer,
- u_long count, void *data)
-{
- user_balloon_op_t bop;
-
- /* Only admin can play with the balloon :) */
- if ( !capable(CAP_SYS_ADMIN) )
- return -EPERM;
-
- if ( copy_from_user(&bop, buffer, sizeof(bop)) )
- return -EFAULT;
-
- switch ( bop.op )
- {
- case USER_INFLATE_BALLOON:
- if ( inflate_balloon(bop.size) < bop.size )
- return -EAGAIN;
- break;
-
- case USER_DEFLATE_BALLOON:
- deflate_balloon(bop.size);
- break;
-
- default:
- printk("Unknown command to balloon driver.");
- return -EFAULT;
- }
-
- return sizeof(bop);
-}
-
-/*
- * main balloon driver initialization function.
- */
-static int __init init_module(void)
-{
- printk(KERN_ALERT "Starting Xeno Balloon driver\n");
-
- credit = 0;
-
- balloon_pde = create_proc_entry(BALLOON_ENTRY, 0600, xeno_base);
- if ( balloon_pde == NULL )
- {
- printk(KERN_ALERT "Unable to create balloon driver proc entry!");
- return -1;
- }
-
- balloon_pde->write_proc = balloon_write;
-
- return 0;
-}
-
-static void __exit cleanup_module(void)
-{
-}
-
-module_init(init_module);
-module_exit(cleanup_module);
-
-
+++ /dev/null
-/******************************************************************************
- * dom_mem_ops.h
- *
- * Header file supporting domain related memory operations. N.B. keep in sync
- * with xen version.
- *
- * Copyright (c) 2003, B Dragovic
- */
-
-#define L1_PROT (_PAGE_PRESENT|_PAGE_RW|_PAGE_USER|_PAGE_ACCESSED)
-#define BALLOON_DEFLATE_OP 0
-#define BALLOON_INFLATE_OP 1
-
-typedef struct balloon_deflate_op {
- unsigned long size;
- unsigned long * pages;
-} balloon_def_op_t;
-
-typedef struct balloon_inflate_op {
- unsigned long size;
- unsigned long * pages;
-} balloon_inf_op_t;
-
-typedef struct dom_mem_ops
-{
- unsigned int op;
- union
- {
- balloon_def_op_t balloon_deflate;
- balloon_inf_op_t balloon_inflate;
- }u;
-} dom_mem_op_t;
+++ /dev/null
-O_TARGET := blk.o
-obj-y := xl_block.o xl_ide.o xl_scsi.o xl_segment.o xl_segment_proc.o
-include $(TOPDIR)/Rules.make
+++ /dev/null
-/******************************************************************************
- * xl_block.c
- *
- * Xenolinux virtual block-device driver.
- *
- */
-
-#include "xl_block.h"
-#include <linux/blk.h>
-#include <linux/cdrom.h>
-
-typedef unsigned char byte; /* from linux/ide.h */
-
-#define XLBLK_RESPONSE_IRQ _EVENT_BLK_RESP
-#define DEBUG_IRQ _EVENT_DEBUG
-
-static blk_ring_t *blk_ring;
-static unsigned int resp_cons; /* Response consumer for comms ring. */
-static unsigned int req_prod; /* Private request producer. */
-static xen_disk_info_t xlblk_disk_info;
-static int xlblk_control_msg_pending;
-
-#define RING_FULL (BLK_RING_INC(req_prod) == resp_cons)
-
-/*
- * Request queues with outstanding work, but ring is currently full.
- * We need no special lock here, as we always access this with the
- * io_request_lock held. We only need a small maximum list.
- */
-#define MAX_PENDING 8
-static request_queue_t *pending_queues[MAX_PENDING];
-static int nr_pending;
-
-static kdev_t sg_dev;
-static int sg_operation = -1;
-static unsigned long sg_next_sect;
-#define DISABLE_SCATTERGATHER() (sg_operation = -1)
-
-static inline void signal_requests_to_xen(void)
-{
- DISABLE_SCATTERGATHER();
- blk_ring->req_prod = req_prod;
- HYPERVISOR_block_io_op();
-}
-
-/* Convert from a XenoLinux major device to the Xen-level 'physical' device */
-inline unsigned short xldev_to_physdev(kdev_t xldev)
-{
- unsigned short physdev = 0;
-
- switch ( MAJOR(xldev) )
- {
- case XLIDE_MAJOR_0:
- physdev = XENDEV_IDE + (0*XLIDE_DEVS_PER_MAJOR) +
- (MINOR(xldev) >> XLIDE_PARTN_SHIFT);
- break;
-
- case XLIDE_MAJOR_1:
- physdev = XENDEV_IDE + (1*XLIDE_DEVS_PER_MAJOR) +
- (MINOR(xldev) >> XLIDE_PARTN_SHIFT);
- break;
-
- case XLSCSI_MAJOR:
- physdev = XENDEV_SCSI + (MINOR(xldev) >> XLSCSI_PARTN_SHIFT);
- break;
-
- case XLVIRT_MAJOR:
- physdev = XENDEV_VIRTUAL + (MINOR(xldev) >> XLVIRT_PARTN_SHIFT);
- break;
- }
-
- if ( physdev == 0 ) BUG();
-
- return physdev;
-}
-
-
-static inline struct gendisk *xldev_to_gendisk(kdev_t xldev)
-{
- struct gendisk *gd = NULL;
-
- switch ( MAJOR(xldev) )
- {
- case XLIDE_MAJOR_0:
- gd = xlide_gendisk[0];
- break;
-
- case XLIDE_MAJOR_1:
- gd = xlide_gendisk[1];
- break;
-
- case XLSCSI_MAJOR:
- gd = xlscsi_gendisk;
- break;
-
- case XLVIRT_MAJOR:
- gd = xlsegment_gendisk;
- break;
- }
-
- if ( gd == NULL ) BUG();
-
- return gd;
-}
-
-
-static inline xl_disk_t *xldev_to_xldisk(kdev_t xldev)
-{
- struct gendisk *gd = xldev_to_gendisk(xldev);
- return (xl_disk_t *)gd->real_devices +
- (MINOR(xldev) >> PARTN_SHIFT(xldev));
-}
-
-
-int xenolinux_block_open(struct inode *inode, struct file *filep)
-{
- xl_disk_t *disk = xldev_to_xldisk(inode->i_rdev);
- disk->usage++;
- DPRINTK("xenolinux_block_open\n");
- return 0;
-}
-
-
-int xenolinux_block_release(struct inode *inode, struct file *filep)
-{
- xl_disk_t *disk = xldev_to_xldisk(inode->i_rdev);
- disk->usage--;
- DPRINTK("xenolinux_block_release\n");
- return 0;
-}
-
-/*
- * handle ioctl calls
- *
- * individual ioctls are defined in /usr/include/linux/fs.h
- */
-
-int xenolinux_block_ioctl(struct inode *inode, struct file *filep,
- unsigned command, unsigned long argument)
-{
- kdev_t dev = inode->i_rdev;
- struct hd_geometry *geo = (struct hd_geometry *)argument;
- struct gendisk *gd;
- struct hd_struct *part;
-
- DPRINTK("xenolinux_block_ioctl\n");
-
- /* check permissions */
- if (!capable(CAP_SYS_ADMIN)) return -EPERM;
- if (!inode) return -EINVAL;
-
- DPRINTK_IOCTL("command: 0x%x, argument: 0x%lx, dev: 0x%04x\n",
- command, (long) argument, dev);
-
- gd = xldev_to_gendisk(dev);
- part = &gd->part[MINOR(dev)];
-
- switch ( command )
- {
- case BLKGETSIZE:
- DPRINTK_IOCTL(" BLKGETSIZE: %x %lx\n", BLKGETSIZE, part->nr_sects);
- return put_user(part->nr_sects, (unsigned long *) argument);
-
- case BLKRRPART: /* re-read partition table */
- DPRINTK_IOCTL(" BLKRRPART: %x\n", BLKRRPART);
- return xenolinux_block_revalidate(dev);
-
- case BLKSSZGET:
- switch ( MAJOR(dev) )
- {
- case XLIDE_MAJOR_0:
- DPRINTK_IOCTL(" BLKSSZGET: %x 0x%x\n", BLKSSZGET,
- xlide_hwsect(MINOR(dev)));
- return xlide_hwsect(MINOR(dev));
-
- case XLSCSI_MAJOR:
- DPRINTK_IOCTL(" BLKSSZGET: %x 0x%x\n", BLKSSZGET,
- xlscsi_hwsect(MINOR(dev)));
- return xlscsi_hwsect(MINOR(dev));
-
- case XLVIRT_MAJOR:
- DPRINTK_IOCTL(" BLKSSZGET: %x 0x%x\n", BLKSSZGET,
- xlsegment_hwsect(MINOR(dev)));
- return xlsegment_hwsect(MINOR(dev));
-
- default:
- printk(KERN_ALERT "BLKSSZGET ioctl() on bogus disk!\n");
- return 0;
- }
-
- case BLKBSZGET: /* get block size */
- DPRINTK_IOCTL(" BLKBSZGET: %x\n", BLKBSZGET);
- break;
-
- case BLKBSZSET: /* set block size */
- DPRINTK_IOCTL(" BLKBSZSET: %x\n", BLKBSZSET);
- break;
-
- case BLKRASET: /* set read-ahead */
- DPRINTK_IOCTL(" BLKRASET: %x\n", BLKRASET);
- break;
-
- case BLKRAGET: /* get read-ahead */
- DPRINTK_IOCTL(" BLKRAFET: %x\n", BLKRAGET);
- break;
-
- case HDIO_GETGEO:
- /* note: these values are complete garbage */
- DPRINTK_IOCTL(" HDIO_GETGEO: %x\n", HDIO_GETGEO);
- if (!argument) return -EINVAL;
- if (put_user(0x00, (unsigned long *) &geo->start)) return -EFAULT;
- if (put_user(0xff, (byte *)&geo->heads)) return -EFAULT;
- if (put_user(0x3f, (byte *)&geo->sectors)) return -EFAULT;
- if (put_user(0x106, (unsigned short *)&geo->cylinders)) return -EFAULT;
- return 0;
-
- case HDIO_GETGEO_BIG:
- /* note: these values are complete garbage */
- DPRINTK_IOCTL(" HDIO_GETGEO_BIG: %x\n", HDIO_GETGEO_BIG);
- if (!argument) return -EINVAL;
- if (put_user(0x00, (unsigned long *) &geo->start)) return -EFAULT;
- if (put_user(0xff, (byte *)&geo->heads)) return -EFAULT;
- if (put_user(0x3f, (byte *)&geo->sectors)) return -EFAULT;
- if (put_user(0x106, (unsigned int *) &geo->cylinders)) return -EFAULT;
- return 0;
-
- case CDROMMULTISESSION:
- printk("FIXME: support multisession CDs later\n");
- memset((struct cdrom_multisession *)argument, 0,
- sizeof(struct cdrom_multisession));
- return 0;
-
- default:
- printk("ioctl %08x not supported by xl_block\n", command);
- return -ENOSYS;
- }
-
- return 0;
-}
-
-int xenolinux_block_check(kdev_t dev)
-{
- DPRINTK("xenolinux_block_check\n");
- return 0;
-}
-
-int xenolinux_block_revalidate(kdev_t dev)
-{
- struct gendisk *gd = xldev_to_gendisk(dev);
- xl_disk_t *disk = xldev_to_xldisk(dev);
- unsigned long flags;
- int i, partn_shift = PARTN_SHIFT(dev);
- int xdev = dev & XENDEV_IDX_MASK;
-
- DPRINTK("xenolinux_block_revalidate: %d %d %d\n",
- dev, xdev, XENDEV_IDX_MASK);
-
- spin_lock_irqsave(&io_request_lock, flags);
- if ( disk->usage > 1 )
- {
- spin_unlock_irqrestore(&io_request_lock, flags);
- return -EBUSY;
- }
- spin_unlock_irqrestore(&io_request_lock, flags);
-
- for ( i = 0; i < (1 << partn_shift); i++ )
- {
- invalidate_device(xdev + i, 1);
- gd->part[xdev + i].start_sect = 0;
- gd->part[xdev + i].nr_sects = 0;
- }
-
- grok_partitions(gd, MINOR(dev) >> partn_shift,
- 1 << partn_shift, disk->capacity);
-
- return 0;
-}
-
-
-/*
- * hypervisor_request
- *
- * request block io
- *
- * id: for guest use only.
- * operation: XEN_BLOCK_{READ,WRITE,PROBE*,SEG*}
- * buffer: buffer to read/write into. this should be a
- * virtual address in the guest os.
- */
-static int hypervisor_request(unsigned long id,
- int operation,
- char * buffer,
- unsigned long sector_number,
- unsigned short nr_sectors,
- kdev_t device)
-{
- unsigned long buffer_ma = phys_to_machine(virt_to_phys(buffer));
- kdev_t phys_device = (kdev_t) 0;
- struct gendisk *gd;
- blk_ring_req_entry_t *req;
- struct buffer_head *bh;
-
- if ( nr_sectors >= (1<<9) ) BUG();
- if ( (buffer_ma & ((1<<9)-1)) != 0 ) BUG();
-
- switch ( operation )
- {
- case XEN_BLOCK_SEG_CREATE:
- case XEN_BLOCK_SEG_DELETE:
- case XEN_BLOCK_PROBE_BLK:
- case XEN_BLOCK_PROBE_SEG:
- if ( RING_FULL ) return 1;
- phys_device = (kdev_t) 0;
- sector_number = 0;
- DISABLE_SCATTERGATHER();
- break;
-
- case XEN_BLOCK_READ:
- case XEN_BLOCK_WRITE:
- phys_device = xldev_to_physdev(device);
- gd = xldev_to_gendisk(device);
-
- sector_number += gd->part[MINOR(device)].start_sect;
- if ( (sg_operation == operation) &&
- (sg_dev == phys_device) &&
- (sg_next_sect == sector_number) )
- {
- req = &blk_ring->ring[(req_prod-1)&(BLK_RING_SIZE-1)].req;
- bh = (struct buffer_head *)id;
- bh->b_reqnext = (struct buffer_head *)req->id;
- req->id = id;
- req->buffer_and_sects[req->nr_segments] = buffer_ma | nr_sectors;
- if ( ++req->nr_segments < MAX_BLK_SEGS )
- sg_next_sect += nr_sectors;
- else
- DISABLE_SCATTERGATHER();
- return 0;
- }
- else if ( RING_FULL )
- {
- return 1;
- }
- else
- {
- sg_operation = operation;
- sg_dev = phys_device;
- sg_next_sect = sector_number + nr_sectors;
- }
- break;
-
- default:
- panic("unknown op %d\n", operation);
- }
-
- /* Fill out a communications ring structure. */
- req = &blk_ring->ring[req_prod].req;
- req->id = id;
- req->operation = operation;
- req->sector_number = sector_number;
- req->device = phys_device;
- req->nr_segments = 1;
- req->buffer_and_sects[0] = buffer_ma | nr_sectors;
- req_prod = BLK_RING_INC(req_prod);
-
- return 0;
-}
-
-
-/*
- * do_xlblk_request
- * read a block; request is in a request queue
- */
-void do_xlblk_request(request_queue_t *rq)
-{
- struct request *req;
- struct buffer_head *bh, *next_bh;
- int rw, nsect, full, queued = 0;
-
- DPRINTK("xlblk.c::do_xlblk_request for '%s'\n", DEVICE_NAME);
-
- while ( !rq->plugged && !list_empty(&rq->queue_head))
- {
- if ( (req = blkdev_entry_next_request(&rq->queue_head)) == NULL )
- goto out;
-
- DPRINTK("do_xlblk_request %p: cmd %i, sec %lx, (%li/%li) bh:%p\n",
- req, req->cmd, req->sector,
- req->current_nr_sectors, req->nr_sectors, req->bh);
-
- rw = req->cmd;
- if ( rw == READA ) rw = READ;
- if ((rw != READ) && (rw != WRITE))
- panic("XenoLinux Virtual Block Device: bad cmd: %d\n", rw);
-
- req->errors = 0;
-
- bh = req->bh;
- while ( bh != NULL )
- {
- next_bh = bh->b_reqnext;
- bh->b_reqnext = NULL;
-
- full = hypervisor_request(
- (unsigned long)bh,
- (rw == READ) ? XEN_BLOCK_READ : XEN_BLOCK_WRITE,
- bh->b_data, bh->b_rsector, bh->b_size>>9, bh->b_rdev);
-
- if ( full )
- {
- bh->b_reqnext = next_bh;
- pending_queues[nr_pending++] = rq;
- if ( nr_pending >= MAX_PENDING ) BUG();
- goto out;
- }
-
- queued++;
-
- /* Dequeue the buffer head from the request. */
- nsect = bh->b_size >> 9;
- bh = req->bh = next_bh;
-
- if ( bh != NULL )
- {
- /* There's another buffer head to do. Update the request. */
- req->hard_sector += nsect;
- req->hard_nr_sectors -= nsect;
- req->sector = req->hard_sector;
- req->nr_sectors = req->hard_nr_sectors;
- req->current_nr_sectors = bh->b_size >> 9;
- req->buffer = bh->b_data;
- }
- else
- {
- /* That was the last buffer head. Finalise the request. */
- if ( end_that_request_first(req, 1, "XenBlk") ) BUG();
- blkdev_dequeue_request(req);
- end_that_request_last(req);
- }
- }
- }
-
- out:
- if ( queued != 0 ) signal_requests_to_xen();
-}
-
-
-static void xlblk_response_int(int irq, void *dev_id, struct pt_regs *ptregs)
-{
- int i;
- unsigned long flags;
- struct buffer_head *bh, *next_bh;
-
- spin_lock_irqsave(&io_request_lock, flags);
-
- for ( i = resp_cons;
- i != blk_ring->resp_prod;
- i = BLK_RING_INC(i) )
- {
- blk_ring_resp_entry_t *bret = &blk_ring->ring[i].resp;
- switch (bret->operation)
- {
- case XEN_BLOCK_READ:
- case XEN_BLOCK_WRITE:
- if ( bret->status )
- printk(KERN_ALERT "Bad return from blkdev data request: %lx\n",
- bret->status);
- for ( bh = (struct buffer_head *)bret->id;
- bh != NULL;
- bh = next_bh )
- {
- next_bh = bh->b_reqnext;
- bh->b_reqnext = NULL;
- bh->b_end_io(bh, !bret->status);
- }
- break;
-
- case XEN_BLOCK_SEG_CREATE:
- case XEN_BLOCK_SEG_DELETE:
- case XEN_BLOCK_PROBE_SEG:
- case XEN_BLOCK_PROBE_BLK:
- if ( bret->status )
- printk(KERN_ALERT "Bad return from blkdev control request\n");
- xlblk_control_msg_pending = 0;
- break;
-
- default:
- BUG();
- }
- }
-
- resp_cons = i;
-
- /* We kick pending request queues if the ring is reasonably empty. */
- if ( (nr_pending != 0) &&
- (((req_prod - resp_cons) & (BLK_RING_SIZE - 1)) <
- (BLK_RING_SIZE >> 1)) )
- {
- /* Attempt to drain the queue, but bail if the ring becomes full. */
- while ( nr_pending != 0 )
- {
- do_xlblk_request(pending_queues[--nr_pending]);
- if ( RING_FULL ) break;
- }
- }
-
- spin_unlock_irqrestore(&io_request_lock, flags);
-}
-
-
-/* Send a synchronous message to Xen. */
-int xenolinux_control_msg(int operation, char *buffer, int size)
-{
- unsigned long flags;
- char *aligned_buf;
-
- /* We copy from an aligned buffer, as interface needs sector alignment. */
- aligned_buf = (char *)get_free_page(GFP_KERNEL);
- if ( aligned_buf == NULL ) BUG();
- memcpy(aligned_buf, buffer, size);
-
- xlblk_control_msg_pending = 1;
- spin_lock_irqsave(&io_request_lock, flags);
- /* Note that size gets rounded up to a sector-sized boundary. */
- if ( hypervisor_request(0, operation, aligned_buf, 0, (size+511)/512, 0) )
- return -EAGAIN;
- signal_requests_to_xen();
- spin_unlock_irqrestore(&io_request_lock, flags);
- while ( xlblk_control_msg_pending ) barrier();
-
- memcpy(buffer, aligned_buf, size);
- free_page((unsigned long)aligned_buf);
-
- return 0;
-}
-
-
-int __init xlblk_init(void)
-{
- int error;
-
- xlblk_control_msg_pending = 0;
- nr_pending = 0;
-
- /* This mapping was created early at boot time. */
- blk_ring = (blk_ring_t *)fix_to_virt(FIX_BLKRING_BASE);
- blk_ring->req_prod = blk_ring->resp_prod = resp_cons = req_prod = 0;
-
- error = request_irq(XLBLK_RESPONSE_IRQ, xlblk_response_int,
- SA_SAMPLE_RANDOM, "xlblk-response", NULL);
- if ( error )
- {
- printk(KERN_ALERT "Could not allocate receive interrupt\n");
- goto fail;
- }
-
- /* Probe for disk information. */
- memset(&xlblk_disk_info, 0, sizeof(xlblk_disk_info));
- error = xenolinux_control_msg(XEN_BLOCK_PROBE_BLK,
- (char *)&xlblk_disk_info,
- sizeof(xen_disk_info_t));
- if ( error )
- {
- printk(KERN_ALERT "Could not probe disks (%d)\n", error);
- free_irq(XLBLK_RESPONSE_IRQ, NULL);
- goto fail;
- }
-
- /* Pass the information to our fake IDE and SCSI susbystems. */
- xlide_init(&xlblk_disk_info);
- xlscsi_init(&xlblk_disk_info);
-
- return 0;
-
- fail:
- return error;
-}
-
-static void __exit xlblk_cleanup(void)
-{
- xlide_cleanup();
- xlscsi_cleanup();
- free_irq(XLBLK_RESPONSE_IRQ, NULL);
-}
-
-
-#ifdef MODULE
-module_init(xlblk_init);
-module_exit(xlblk_cleanup);
-#endif
+++ /dev/null
-/******************************************************************************
- * xl_block.h
- *
- * Shared definitions between all levels of XenoLinux Virtual block devices.
- */
-
-#ifndef __XL_BLOCK_H__
-#define __XL_BLOCK_H__
-
-#include <linux/config.h>
-#include <linux/module.h>
-
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/slab.h>
-#include <linux/string.h>
-#include <linux/errno.h>
-
-#include <linux/fs.h>
-#include <linux/hdreg.h>
-#include <linux/blkdev.h>
-#include <linux/major.h>
-
-#include <asm/hypervisor-ifs/block.h>
-#include <asm/hypervisor-ifs/hypervisor-if.h>
-#include <asm/io.h>
-#include <asm/atomic.h>
-#include <asm/uaccess.h>
-
-#if 0
-#define DPRINTK(_f, _a...) printk ( KERN_ALERT _f , ## _a )
-#else
-#define DPRINTK(_f, _a...) ((void)0)
-#endif
-
-#if 0
-#define DPRINTK_IOCTL(_f, _a...) printk ( KERN_ALERT _f , ## _a )
-#else
-#define DPRINTK_IOCTL(_f, _a...) ((void)0)
-#endif
-
-/* XL IDE and SCSI use same major/minor numbers as normal Linux devices. */
-#define XLIDE_MAJOR_0 IDE0_MAJOR
-#define XLIDE_MAJOR_1 IDE1_MAJOR
-#define XLSCSI_MAJOR SCSI_DISK0_MAJOR
-
-#define XLIDE_PARTN_SHIFT 6
-#define XLSCSI_PARTN_SHIFT 4
-#define XLVIRT_PARTN_SHIFT 4
-
-static inline int PARTN_SHIFT(kdev_t dev)
-{
- switch ( MAJOR(dev) )
- {
- case XLIDE_MAJOR_0:
- case XLIDE_MAJOR_1:
- return XLIDE_PARTN_SHIFT;
- case XLSCSI_MAJOR:
- return XLSCSI_PARTN_SHIFT;
- case XLVIRT_MAJOR:
- return XLVIRT_PARTN_SHIFT;
- default:
- BUG();
- }
-}
-
-#define XLIDE_DEVS_PER_MAJOR 2
-#define XLSCSI_DEVS_PER_MAJOR 16
-#define XLVIRT_DEVS_PER_MAJOR 16
-
-/*
- * We have one of these per XL-IDE, XL-SCSI, and XL-VIRT device.
- * They hang in an array off the gendisk structure. We may end up putting
- * all kinds of interesting stuff here :-)
- */
-typedef struct xl_disk {
- int usage;
- unsigned long capacity;
-} xl_disk_t;
-
-/* Generic layer. */
-extern int xenolinux_control_msg(int operration, char *buffer, int size);
-extern int xenolinux_block_open(struct inode *inode, struct file *filep);
-extern int xenolinux_block_release(struct inode *inode, struct file *filep);
-extern int xenolinux_block_ioctl(struct inode *inode, struct file *filep,
- unsigned command, unsigned long argument);
-extern int xenolinux_block_check(kdev_t dev);
-extern int xenolinux_block_revalidate(kdev_t dev);
-extern void do_xlblk_request (request_queue_t *rq);
-
-/* Fake IDE subsystem. */
-extern int xlide_init(xen_disk_info_t *xdi);
-extern int xlide_hwsect(int minor);
-extern void xlide_cleanup(void);
-extern struct gendisk *xlide_gendisk[];
-
-/* Fake SCSI subsystem. */
-extern int xlscsi_init(xen_disk_info_t *xdi);
-extern int xlscsi_hwsect(int minor);
-extern void xlscsi_cleanup(void);
-extern struct gendisk *xlscsi_gendisk;
-
-/* Virtual block-device subsystem. */
-extern int xlsegment_hwsect(int minor);
-extern struct gendisk *xlsegment_gendisk;
-
-#endif /* __XL_BLOCK_H__ */
+++ /dev/null
-/******************************************************************************
- * xl_ide.c
- *
- * Xenolinux virtual IDE block-device driver.
- */
-
-#include "xl_block.h"
-#include <linux/blk.h>
-
-#define XLIDE_MAX 256
-#define XLIDE_MAJOR_NAME "hd"
-static int xlide_blksize_size[XLIDE_MAX];
-static int xlide_hardsect_size[XLIDE_MAX];
-static int xlide_max_sectors[XLIDE_MAX];
-
-#define XLIDE_NR_MAJORS 2
-
-struct gendisk *xlide_gendisk[XLIDE_NR_MAJORS] = { NULL };
-
-static struct block_device_operations xlide_block_fops =
-{
- open: xenolinux_block_open,
- release: xenolinux_block_release,
- ioctl: xenolinux_block_ioctl,
- check_media_change: xenolinux_block_check,
- revalidate: xenolinux_block_revalidate,
-};
-
-int xlide_hwsect(int minor)
-{
- return xlide_hardsect_size[minor];
-}
-
-static int get_major(int major)
-{
- int r = register_blkdev(major, XLIDE_MAJOR_NAME, &xlide_block_fops);
- if ( r < 0 )
- printk (KERN_ALERT "XL IDE: can't get major %d\n", XLIDE_MAJOR_0);
- return r;
-}
-
-static void setup_major(struct gendisk **pgd,
- xen_disk_info_t *xdi, int base, int major)
-{
- int i, minors, disk, units = XLIDE_DEVS_PER_MAJOR;
- unsigned short minor;
- unsigned char buf[64];
- struct gendisk *gd;
-
- blk_size[major] = NULL;
- blksize_size[major] = xlide_blksize_size + base*(1<<XLIDE_PARTN_SHIFT);
- hardsect_size[major] = xlide_hardsect_size + base*(1<<XLIDE_PARTN_SHIFT);
- max_sectors[major] = xlide_max_sectors + base*(1<<XLIDE_PARTN_SHIFT);
- read_ahead[major] = 8;
-
- blk_init_queue(BLK_DEFAULT_QUEUE(major), do_xlblk_request);
-
- /*
- * Turn off barking 'headactive' mode. We dequeue buffer heads as soon as
- * we pass them down to Xen.
- */
- blk_queue_headactive(BLK_DEFAULT_QUEUE(major), 0);
-
- /* Construct an appropriate gendisk structure. */
- minors = units * (1<<XLIDE_PARTN_SHIFT);
- gd = kmalloc(sizeof(struct gendisk), GFP_KERNEL);
- gd->sizes = kmalloc(minors * sizeof(int), GFP_KERNEL);
- gd->part = kmalloc(minors * sizeof(struct hd_struct), GFP_KERNEL);
- gd->major = major;
- gd->major_name = XLIDE_MAJOR_NAME;
- gd->minor_shift = XLIDE_PARTN_SHIFT;
- gd->max_p = 1<<XLIDE_PARTN_SHIFT;
- gd->nr_real = units;
- gd->real_devices = kmalloc(units * sizeof(xl_disk_t), GFP_KERNEL);
- gd->next = NULL;
- gd->fops = &xlide_block_fops;
- gd->de_arr = kmalloc(sizeof(*gd->de_arr) * units, GFP_KERNEL);
- gd->flags = kmalloc(sizeof(*gd->flags) * units, GFP_KERNEL);
- memset(gd->sizes, 0, minors * sizeof(int));
- memset(gd->part, 0, minors * sizeof(struct hd_struct));
- memset(gd->de_arr, 0, sizeof(*gd->de_arr) * units);
- memset(gd->flags, 0, sizeof(*gd->flags) * units);
- memset(gd->real_devices, 0, sizeof(xl_disk_t) * units);
- *pgd = gd;
- add_gendisk(gd);
-
- /* Now register each disk in turn. */
- for ( i = 0; i < xdi->count; i++ )
- {
- disk = xdi->disks[i].device & XENDEV_IDX_MASK;
- minor = (disk-base) << XLIDE_PARTN_SHIFT;
-
- if ( !IS_IDE_XENDEV(xdi->disks[i].device) ||
- (disk < base) || (disk >= (base + XLIDE_DEVS_PER_MAJOR)) )
- continue;
-
- ((xl_disk_t *)gd->real_devices)[disk].capacity =
- xdi->disks[i].capacity;
-
- switch (xdi->disks[i].type)
- {
- case XD_TYPE_CDROM:
- set_device_ro(MKDEV(major, minor), 1);
-
- case XD_TYPE_FLOPPY:
- case XD_TYPE_TAPE:
- gd->flags[disk] = GENHD_FL_REMOVABLE;
- printk(KERN_ALERT "Skipping partition check on %s /dev/%s\n",
- xdi->disks[i].type==XD_TYPE_CDROM ? "cdrom" :
- (xdi->disks[i].type==XD_TYPE_TAPE ? "tape" : "floppy"),
- disk_name(gd, minor, buf));
- break;
-
- case XD_TYPE_DISK:
- register_disk(gd,
- MKDEV(major, minor),
- 1<<XLIDE_PARTN_SHIFT,
- &xlide_block_fops, xdi->disks[i].capacity);
- break;
-
- default:
- printk(KERN_ALERT "XenoLinux: unknown ide device type %d\n",
- xdi->disks[i].type);
- break;
- }
- }
-
- return gd;
-}
-
-
-int xlide_init(xen_disk_info_t *xdi)
-{
- int i, units;
-
- /* If we don't have any usable IDE devices we may as well bail now. */
- units = 0;
- for ( i = 0; i < xdi->count; i++ )
- if ( IS_IDE_XENDEV(xdi->disks[i].device) &&
- ((xdi->disks[i].device & XENDEV_IDX_MASK) <
- (XLIDE_NR_MAJORS*XLIDE_DEVS_PER_MAJOR)) )
- units++;
- if ( units == 0 ) return 0;
-
- SET_MODULE_OWNER(&xlide_block_fops);
-
- if ( get_major(XLIDE_MAJOR_0) < 0 )
- return 0;
- if ( get_major(XLIDE_MAJOR_1) < 0 )
- {
- (void)unregister_blkdev(XLIDE_MAJOR_0, XLIDE_MAJOR_NAME);
- return 0;
- }
-
- /* Initialize global arrays. */
- for ( i = 0; i < XLIDE_MAX; i++ )
- {
- xlide_blksize_size[i] = 512;
- xlide_hardsect_size[i] = 512;
- xlide_max_sectors[i] = 128;
- }
-
- setup_major(&xlide_gendisk[0], xdi, 0*XLIDE_DEVS_PER_MAJOR, XLIDE_MAJOR_0);
- setup_major(&xlide_gendisk[1], xdi, 1*XLIDE_DEVS_PER_MAJOR, XLIDE_MAJOR_1);
-
- return 0;
-}
-
-
-static void cleanup_major(int major)
-{
- blk_cleanup_queue(BLK_DEFAULT_QUEUE(major));
-
- read_ahead[major] = 0;
-
- if ( blksize_size[major] != NULL )
- {
- kfree(blksize_size[major]);
- blksize_size[major] = NULL;
- }
-
- if ( hardsect_size[major] != NULL )
- {
- kfree(hardsect_size[major]);
- hardsect_size[major] = NULL;
- }
-
- if ( max_sectors[major] != NULL )
- {
- kfree(max_sectors[major]);
- max_sectors[major] = NULL;
- }
-
- (void)unregister_blkdev(major, XLIDE_MAJOR_NAME);
-}
-
-void xlide_cleanup(void)
-{
- if ( xlide_gendisk[0] == NULL ) return;
- xlide_gendisk[0] = NULL;
- cleanup_major(XLIDE_MAJOR_0);
- cleanup_major(XLIDE_MAJOR_1);
-}
-
+++ /dev/null
-/******************************************************************************
- * xl_scsi.c
- *
- * Xenolinux virtual SCSI block-device driver.
- */
-
-#include "xl_block.h"
-
-#define MAJOR_NR XLSCSI_MAJOR
-#include <linux/blk.h>
-
-#define XLSCSI_MAX 256
-#define XLSCSI_MAJOR_NAME "sd"
-static int xlscsi_blksize_size[XLSCSI_MAX];
-static int xlscsi_hardsect_size[XLSCSI_MAX];
-static int xlscsi_max_sectors[XLSCSI_MAX];
-
-struct gendisk *xlscsi_gendisk = NULL;
-
-static struct block_device_operations xlscsi_block_fops =
-{
- open: xenolinux_block_open,
- release: xenolinux_block_release,
- ioctl: xenolinux_block_ioctl,
- check_media_change: xenolinux_block_check,
- revalidate: xenolinux_block_revalidate,
-};
-
-
-/* tiny inteface fn */
-int xlscsi_hwsect(int minor)
-{
- return xlscsi_hardsect_size[minor];
-}
-
-
-int xlscsi_init(xen_disk_info_t *xdi)
-{
- int i, result, units, minors, disk;
- struct gendisk *gd;
-
- /* If we don't have any usable SCSI devices we may as well bail now. */
- units = 0;
- for ( i = 0; i < xdi->count; i++ )
- if ( IS_SCSI_XENDEV(xdi->disks[i].device) &&
- ((xdi->disks[i].device & XENDEV_IDX_MASK) <
- XLSCSI_DEVS_PER_MAJOR) )
- units++;
- if ( units == 0 ) return 0;
-
- SET_MODULE_OWNER(&xlscsi_block_fops);
-
- result = register_blkdev(XLSCSI_MAJOR, XLSCSI_MAJOR_NAME,
- &xlscsi_block_fops);
- if ( result < 0 )
- {
- printk (KERN_ALERT "XL SCSI: can't get major %d\n", XLSCSI_MAJOR);
- return result;
- }
-
- /* Initialize global arrays. */
- for ( i = 0; i < XLSCSI_MAX; i++ )
- {
- xlscsi_blksize_size[i] = 1024; //XXX 512;
- xlscsi_hardsect_size[i] = 512;
- xlscsi_max_sectors[i] = 128*8; //XXX 128
- }
-
- blk_size[XLSCSI_MAJOR] = NULL;
- blksize_size[XLSCSI_MAJOR] = xlscsi_blksize_size;
- hardsect_size[XLSCSI_MAJOR] = xlscsi_hardsect_size;
- max_sectors[XLSCSI_MAJOR] = xlscsi_max_sectors;
- read_ahead[XLSCSI_MAJOR] = NULL; //XXX8;
-
- blk_init_queue(BLK_DEFAULT_QUEUE(XLSCSI_MAJOR), do_xlblk_request);
-
- /*
- * Turn off barking 'headactive' mode. We dequeue buffer heads as
- * soon as we pass them down to Xen.
- */
- blk_queue_headactive(BLK_DEFAULT_QUEUE(XLSCSI_MAJOR), 0);
-
- units = XLSCSI_MAX >> XLSCSI_PARTN_SHIFT;
-
- /* Construct an appropriate gendisk structure. */
- minors = units * (1<<XLSCSI_PARTN_SHIFT);
- gd = kmalloc(sizeof(struct gendisk), GFP_KERNEL);
- gd->sizes = kmalloc(minors * sizeof(int), GFP_KERNEL);
- gd->part = kmalloc(minors * sizeof(struct hd_struct), GFP_KERNEL);
- gd->major = XLSCSI_MAJOR;
- gd->major_name = XLSCSI_MAJOR_NAME;
- gd->minor_shift = XLSCSI_PARTN_SHIFT;
- gd->max_p = 1<<XLSCSI_PARTN_SHIFT;
- gd->nr_real = units;
- gd->real_devices = kmalloc(units * sizeof(xl_disk_t), GFP_KERNEL);
- gd->next = NULL;
- gd->fops = &xlscsi_block_fops;
- gd->de_arr = kmalloc(sizeof(*gd->de_arr) * units, GFP_KERNEL);
- gd->flags = kmalloc(sizeof(*gd->flags) * units, GFP_KERNEL);
- memset(gd->sizes, 0, minors * sizeof(int));
- memset(gd->part, 0, minors * sizeof(struct hd_struct));
- memset(gd->de_arr, 0, sizeof(*gd->de_arr) * units);
- memset(gd->flags, 0, sizeof(*gd->flags) * units);
- memset(gd->real_devices, 0, sizeof(xl_disk_t) * units);
- xlscsi_gendisk = gd;
- add_gendisk(gd);
-
- /* Now register each disk in turn. */
- for ( i = 0; i < xdi->count; i++ )
- {
- disk = xdi->disks[i].device & XENDEV_IDX_MASK;
-
- if ( !IS_SCSI_XENDEV(xdi->disks[i].device) ||
- (disk >= XLSCSI_DEVS_PER_MAJOR) )
- continue;
-
- ((xl_disk_t *)gd->real_devices)[disk].capacity =
- xdi->disks[i].capacity;
- register_disk(gd,
- MKDEV(XLSCSI_MAJOR, disk<<XLSCSI_PARTN_SHIFT),
- 1<<XLSCSI_PARTN_SHIFT,
- &xlscsi_block_fops,
- xdi->disks[i].capacity);
- }
-
- printk(KERN_ALERT
- "XenoLinux Virtual SCSI Device Driver installed [device: %d]\n",
- XLSCSI_MAJOR);
-
- return 0;
-}
-
-
-void xlscsi_cleanup(void)
-{
- if ( xlscsi_gendisk == NULL ) return;
-
- blk_cleanup_queue(BLK_DEFAULT_QUEUE(XLSCSI_MAJOR));
-
- xlscsi_gendisk = NULL;
-
- read_ahead[XLSCSI_MAJOR] = 0;
-
- if ( blksize_size[XLSCSI_MAJOR] != NULL )
- {
- kfree(blksize_size[XLSCSI_MAJOR]);
- blksize_size[XLSCSI_MAJOR] = NULL;
- }
-
- if ( hardsect_size[XLSCSI_MAJOR] != NULL )
- {
- kfree(hardsect_size[XLSCSI_MAJOR]);
- hardsect_size[XLSCSI_MAJOR] = NULL;
- }
-
- if ( max_sectors[XLSCSI_MAJOR] != NULL )
- {
- kfree(max_sectors[XLSCSI_MAJOR]);
- max_sectors[XLSCSI_MAJOR] = NULL;
- }
-
- if ( unregister_blkdev(XLSCSI_MAJOR, XLSCSI_MAJOR_NAME) != 0 )
- {
- printk(KERN_ALERT
- "XenoLinux Virtual SCSI Device Driver uninstalled w/ errs\n");
- }
-}
-
+++ /dev/null
-/******************************************************************************
- * xl_segment.c
- *
- * Xenolinux virtual block-device driver (xvd).
- *
- */
-
-#include "xl_block.h"
-
-#define MAJOR_NR XLVIRT_MAJOR
-#include <linux/blk.h>
-
-/* Copied from linux/ide.h */
-typedef unsigned char byte;
-
-#define XLVIRT_MAX 256
-#define XLVIRT_MAJOR_NAME "xvd"
-static int xlseg_blksize_size[XLVIRT_MAX];
-static int xlseg_hardsect_size[XLVIRT_MAX];
-static int xlseg_max_sectors[XLVIRT_MAX];
-
-struct gendisk *xlsegment_gendisk = NULL;
-
-static xen_disk_info_t xlseg_disk_info;
-
-static struct block_device_operations xlsegment_block_fops =
-{
- open: xenolinux_block_open,
- release: xenolinux_block_release,
- ioctl: xenolinux_block_ioctl,
- check_media_change: xenolinux_block_check,
- revalidate: xenolinux_block_revalidate,
-};
-
-
-int xlsegment_hwsect(int minor)
-{
- return xlseg_hardsect_size[minor];
-}
-
-
-int __init xlseg_init(void)
-{
- int i, result, units, minors, disk;
- xen_disk_info_t *xdi = &xlseg_disk_info;
- struct gendisk *gd;
-
- SET_MODULE_OWNER(&xlsegment_block_fops);
-
- /* Probe for disk information. */
- memset(xdi, 0, sizeof(*xdi));
- xenolinux_control_msg(XEN_BLOCK_PROBE_SEG, (char *)xdi, sizeof(*xdi));
-
- DPRINTK("xvd block device probe:\n");
- for ( i = 0; i < xdi->count; i++ )
- {
- DPRINTK(" %2d: device: %d, capacity: %ld\n",
- i, xdi->disks[i].device, xdi->disks[i].capacity);
- }
-
- result = register_blkdev(XLVIRT_MAJOR, XLVIRT_MAJOR_NAME,
- &xlsegment_block_fops);
- if ( result < 0 )
- {
- printk(KERN_ALERT "XL Segment: can't get major %d\n", XLVIRT_MAJOR);
- return result;
- }
-
- /* Initialize global arrays. */
- for (i = 0; i < XLVIRT_MAX; i++)
- {
- xlseg_blksize_size[i] = 512;
- xlseg_hardsect_size[i] = 512;
- xlseg_max_sectors[i] = 128;
- }
-
- blk_size[XLVIRT_MAJOR] = NULL;
- blksize_size[XLVIRT_MAJOR] = xlseg_blksize_size;
- hardsect_size[XLVIRT_MAJOR] = xlseg_hardsect_size;
- max_sectors[XLVIRT_MAJOR] = xlseg_max_sectors;
- read_ahead[XLVIRT_MAJOR] = 8;
-
- blk_init_queue(BLK_DEFAULT_QUEUE(XLVIRT_MAJOR), do_xlblk_request);
-
- /*
- * Turn off barking 'headactive' mode. We dequeue buffer heads as
- * soon as we pass them down to Xen.
- */
- blk_queue_headactive(BLK_DEFAULT_QUEUE(XLVIRT_MAJOR), 0);
-
- units = XLVIRT_MAX >> XLVIRT_PARTN_SHIFT;
-
- /* Construct an appropriate gendisk structure. */
- minors = units * (1<<XLVIRT_PARTN_SHIFT);
- gd = kmalloc(sizeof(struct gendisk), GFP_KERNEL);
- gd->sizes = kmalloc(minors * sizeof(int), GFP_KERNEL);
- gd->part = kmalloc(minors * sizeof(struct hd_struct), GFP_KERNEL);
- gd->major = XLVIRT_MAJOR;
- gd->major_name = XLVIRT_MAJOR_NAME;
- gd->minor_shift = XLVIRT_PARTN_SHIFT;
- gd->max_p = 1<<XLVIRT_PARTN_SHIFT;
- gd->nr_real = units;
- gd->real_devices = kmalloc(units * sizeof(xl_disk_t), GFP_KERNEL);
- gd->next = NULL;
- gd->fops = &xlsegment_block_fops;
- gd->de_arr = kmalloc(sizeof(*gd->de_arr) * units, GFP_KERNEL);
- gd->flags = kmalloc(sizeof(*gd->flags) * units, GFP_KERNEL);
- memset(gd->sizes, 0, minors * sizeof(int));
- memset(gd->part, 0, minors * sizeof(struct hd_struct));
- memset(gd->de_arr, 0, sizeof(*gd->de_arr) * units);
- memset(gd->flags, 0, sizeof(*gd->flags) * units);
- memset(gd->real_devices, 0, sizeof(xl_disk_t) * units);
- xlsegment_gendisk = gd;
- add_gendisk(gd);
-
- /* Now register each disk in turn. */
- for ( i = 0; i < xdi->count; i++ )
- {
- disk = xdi->disks[i].device & XENDEV_IDX_MASK;
-
- if ( !IS_VIRTUAL_XENDEV(xdi->disks[i].device) ||
- (disk >= XLVIRT_DEVS_PER_MAJOR) )
- continue;
-
- ((xl_disk_t *)gd->real_devices)[disk].capacity =
- xdi->disks[i].capacity;
- register_disk(gd,
- MKDEV(XLVIRT_MAJOR, disk<<XLVIRT_PARTN_SHIFT),
- 1<<XLVIRT_PARTN_SHIFT,
- &xlsegment_block_fops,
- xdi->disks[i].capacity);
- }
-
- printk(KERN_ALERT
- "XenoLinux Virtual Segment Device Driver installed [device: %d]\n",
- XLVIRT_MAJOR);
-
- return 0;
-}
-
-
-static void __exit xlseg_cleanup(void)
-{
- if ( xlsegment_gendisk == NULL ) return;
-
- blk_cleanup_queue(BLK_DEFAULT_QUEUE(XLVIRT_MAJOR));
-
- xlsegment_gendisk = NULL;
-
- read_ahead[XLVIRT_MAJOR] = 0;
-
- if ( blksize_size[XLVIRT_MAJOR] != NULL )
- {
- kfree(blksize_size[XLVIRT_MAJOR]);
- blksize_size[XLVIRT_MAJOR] = NULL;
- }
-
- if ( hardsect_size[XLVIRT_MAJOR] != NULL )
- {
- kfree(hardsect_size[XLVIRT_MAJOR]);
- hardsect_size[XLVIRT_MAJOR] = NULL;
- }
-
- if ( max_sectors[XLVIRT_MAJOR] != NULL )
- {
- kfree(max_sectors[XLVIRT_MAJOR]);
- max_sectors[XLVIRT_MAJOR] = NULL;
- }
-
- if ( unregister_blkdev(XLVIRT_MAJOR, XLVIRT_MAJOR_NAME) != 0 )
- {
- printk(KERN_ALERT
- "XenoLinux Virtual Segment Device Driver"
- " uninstalled w/ errs\n");
- }
-}
-
-
-#ifdef MODULE
-module_init(xlseg_init);
-module_exit(xlseg_cleanup);
-#endif
+++ /dev/null
-/*
- * xl_segment_proc.c
- *
- * XenoLinux virtual disk proc interface .
- */
-
-#include "xl_block.h"
-#include <linux/proc_fs.h>
-#include <linux/delay.h>
-
-static struct proc_dir_entry *vhd;
-
-static int proc_read_vhd(char *page, char **start, off_t off,
- int count, int *eof, void *data)
-{
- return 0;
-}
-
-#define isdelim(c) \
- (c==' '||c==','||c=='\n'||c=='\r'||c=='\t'||c==':'||c=='('||c==')' ? 1 : 0)
-
-char *get_string(char *string) /* a bit like strtok */
-{
- static char *temp;
- int loop = 0;
-
- if (string != NULL)
- temp = string;
- else
- string = temp;
-
- try_again:
-
- while (!isdelim(string[loop]))
- {
- if (string[loop] == '\0')
- return NULL;
- loop++;
- }
-
- string[loop] = '\0';
- temp = (string + loop + 1);
-
- if (loop == 0)
- {
- string = temp;
- goto try_again;
- }
-
- return string;
-}
-
-
-#define isdigit(c) (c >= '0' && c <= '9' ? 1 : 0)
-unsigned long to_number(char *string) /* atoi */
-{
- unsigned long value = 0;
-
- if (string == NULL) return 0;
-
- while (!isdigit(*string) && *string != '\0') string++;
-
- while (isdigit(*string))
- {
- value = value * 10 + (*string - '0');
- string++;
- }
-
- return value;
-}
-
-static int proc_write_vhd(struct file *file, const char *buffer,
- unsigned long count, void *data)
-{
- char *local = kmalloc((count + 1) * sizeof(char), GFP_KERNEL);
- char *string;
- int loop;
- xv_disk_t xvd;
-
- memset (&xvd, 0, sizeof(xvd));
-
- if (copy_from_user(local, buffer, count))
- {
- return -EFAULT;
- }
- local[count] = '\0';
-
- string = get_string(local); /* domain specifier */
- if (string == NULL)
- {
- return count;
- }
- if (*string != 'd' && *string != 'D')
- {
- printk (KERN_ALERT
- "error: domain specifier missing [%s]. should be \"domain\".\n",
- string);
- return count;
- }
-
- string = get_string(NULL); /* domain number */
- if (string == NULL)
- {
- printk (KERN_ALERT "error: domain number missing\n");
- return count;
- }
- xvd.domain = (int) to_number(string);
-
- string = get_string(NULL);
- if (string && (strcmp(string, "RO") == 0 || strcmp(string, "ro") == 0))
- {
- xvd.mode = XEN_DISK_READ_ONLY;
- }
- else if (string && (strcmp(string, "RW") == 0 || strcmp(string, "rw") == 0))
- {
- xvd.mode = XEN_DISK_READ_WRITE;
- }
- else
- {
- printk (KERN_ALERT
- "error: bad mode [%s]. should be \"rw\" or \"ro\".\n",
- string);
- return count;
- }
-
- string = get_string(NULL); /* look for Segment */
- if (string == NULL || (*string != 's' && *string != 'S'))
- {
- printk (KERN_ALERT
- "error: segment specifier missing [%s]. should be \"segment\".\n",
- string);
- return count;
- }
-
- string = get_string(NULL); /* segment number */
- if (string == NULL)
- {
- printk (KERN_ALERT "error: segment number missing\n");
- return count;
- }
- xvd.segment = (int) to_number(string);
-
- string = get_string(NULL); /* look for Extents */
- if (string == NULL || (*string != 'e' && *string != 'E'))
- {
- printk (KERN_ALERT
- "error: extents specifier missing [%s]. should be \"extents\".\n",
- string);
- return count;
- }
-
- string = get_string(NULL); /* number of extents */
- if (string == NULL)
- {
- printk (KERN_ALERT "error: number of extents missing\n");
- return count;
- }
- xvd.ext_count = (int) to_number(string);
-
- /* ignore parenthesis */
-
- for (loop = 0; loop < xvd.ext_count; loop++)
- {
- string = get_string(NULL); /* look for Disk */
- if (string == NULL || (*string != 'd' && *string != 'D'))
- {
- printk (KERN_ALERT
- "hmm, extent disk specifier missing [%s]. should be \"disk\".\n",
- string);
- return count;
- }
- string = get_string(NULL); /* disk number */
- if (string == NULL)
- {
- printk (KERN_ALERT "error: disk number missing\n");
- return count;
- }
- xvd.extents[loop].disk = xldev_to_physdev((int) to_number(string));
-
- string = get_string(NULL); /* look for Offset */
- if (string == NULL || (*string != 'o' && *string != 'O'))
- {
- printk (KERN_ALERT
- "error: disk offset missing [%s]. should be \"offset\".\n",
- string);
- return count;
- }
- string = get_string(NULL); /* offset */
- if (string == NULL)
- {
- printk (KERN_ALERT "error: offset missing\n");
- return count;
- }
- xvd.extents[loop].offset = to_number(string);
-
- string = get_string(NULL); /* look for Size */
- if (string == NULL || (*string != 's' && *string != 'S'))
- {
- printk (KERN_ALERT
- "error: extent size missing [%s]. should be \"size\".\n",
- string);
- return count;
- }
- string = get_string(NULL); /* size */
- if (string == NULL)
- {
- printk (KERN_ALERT "error: extent size missing\n");
- return count;
- }
- xvd.extents[loop].size = to_number(string);
- }
-
- xenolinux_control_msg(XEN_BLOCK_SEG_CREATE, (char *)&xvd, sizeof(xvd));
-
- return count;
-}
-
-/******************************************************************/
-
-int __init xlseg_proc_init(void)
-{
- vhd = create_proc_entry("xeno/dom0/vhd", 0644, NULL);
- if (vhd == NULL)
- {
- panic ("xlseg_init: unable to create vhd proc entry\n");
- }
- vhd->data = NULL;
- vhd->read_proc = proc_read_vhd;
- vhd->write_proc = proc_write_vhd;
- vhd->owner = THIS_MODULE;
-
- printk(KERN_ALERT "XenoLinux Virtual Disk Device Monitor installed\n");
- return 0;
-}
-
-static void __exit xlseg_proc_cleanup(void)
-{
- printk(KERN_ALERT "XenoLinux Virtual Disk Device Monitor uninstalled\n");
-}
-
-#ifdef MODULE
-module_init(xlseg_proc_init);
-module_exit(xlseg_proc_cleanup);
-#endif
+++ /dev/null
-O_TARGET := con.o
-obj-$(CONFIG_XEN_CONSOLE) := console.o
-include $(TOPDIR)/Rules.make
+++ /dev/null
-/******************************************************************************
- * console.c
- */
-
-#include <linux/config.h>
-#include <linux/module.h>
-#include <linux/errno.h>
-#include <linux/signal.h>
-#include <linux/sched.h>
-#include <linux/interrupt.h>
-#include <linux/tty.h>
-#include <linux/tty_flip.h>
-#include <linux/serial.h>
-#include <linux/major.h>
-#include <linux/ptrace.h>
-#include <linux/ioport.h>
-#include <linux/mm.h>
-#include <linux/slab.h>
-#include <linux/init.h>
-#include <linux/console.h>
-
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/uaccess.h>
-#include <asm/hypervisor.h>
-
-#define XENO_TTY_MINOR 123
-
-/******************** Kernel console driver ********************************/
-
-static void xen_console_write(struct console *co, const char *s, unsigned count)
-{
-#define STRLEN 256
- static char str[STRLEN];
- static int pos = 0;
- int len;
-
- /* We buffer output until we see a newline, or until the buffer is full. */
- while ( count != 0 )
- {
- len = ((STRLEN - pos) > count) ? count : STRLEN - pos;
- memcpy(str + pos, s, len);
- pos += len;
- s += len;
- count -= len;
- if ( (pos == STRLEN) || (str[pos-1] == '\n') )
- {
- (void)HYPERVISOR_console_write(str, pos);
- pos = 0;
- }
- }
-}
-
-static kdev_t xen_console_device(struct console *c)
-{
- /*
- * This is the magic that binds our "struct console" to our
- * "tty_struct", defined below.
- */
- return MKDEV(TTY_MAJOR, XENO_TTY_MINOR);
-}
-
-static struct console xen_console_info = {
- name: "xen_console",
- write: xen_console_write,
- device: xen_console_device,
- flags: CON_PRINTBUFFER,
- index: -1,
-};
-
-void xen_console_init(void)
-{
- register_console(&xen_console_info);
-}
-
-
-/******************** Initial /dev/console *********************************/
-
-
-static struct tty_driver xeno_console_driver;
-static int xeno_console_refcount;
-static struct tty_struct *xeno_console_table[1];
-static struct termios *xeno_console_termios[1];
-static struct termios *xeno_console_termios_locked[1];
-
-static int xeno_console_write_room(struct tty_struct *tty)
-{
- return INT_MAX;
-}
-
-static int xeno_console_chars_in_buffer(struct tty_struct *tty)
-{
- return 0;
-}
-
-static inline int xeno_console_xmit(int ch)
-{
- char _ch = ch;
- xen_console_write(NULL, &_ch, 1);
- return 1;
-}
-
-static int xeno_console_write(struct tty_struct *tty, int from_user,
- const u_char * buf, int count)
-{
- int i;
-
- if ( from_user && verify_area(VERIFY_READ, buf, count) )
- {
- return -EINVAL;
- }
-
- for ( i = 0; i < count; i++ )
- {
- char ch;
- if ( from_user )
- {
- __get_user(ch, buf + i);
- }
- else
- {
- ch = buf[i];
- }
- xeno_console_xmit(ch);
- }
- return i;
-}
-
-static void xeno_console_put_char(struct tty_struct *tty, u_char ch)
-{
- xeno_console_xmit(ch);
-}
-
-static int xeno_console_open(struct tty_struct *tty, struct file *filp)
-{
- int line;
-
- MOD_INC_USE_COUNT;
- line = MINOR(tty->device) - tty->driver.minor_start;
- if ( line )
- {
- MOD_DEC_USE_COUNT;
- return -ENODEV;
- }
-
- tty->driver_data = NULL;
-
- return 0;
-}
-
-static void xeno_console_close(struct tty_struct *tty, struct file *filp)
-{
- MOD_DEC_USE_COUNT;
-}
-
-int __init xeno_con_init(void)
-{
- memset(&xeno_console_driver, 0, sizeof(struct tty_driver));
- xeno_console_driver.magic = TTY_DRIVER_MAGIC;
- xeno_console_driver.driver_name = "xeno_console";
- xeno_console_driver.name = "xencon";
- xeno_console_driver.major = TTY_MAJOR;
- xeno_console_driver.minor_start = XENO_TTY_MINOR;
- xeno_console_driver.num = 1;
- xeno_console_driver.type = TTY_DRIVER_TYPE_SERIAL;
- xeno_console_driver.subtype = SERIAL_TYPE_NORMAL;
- xeno_console_driver.init_termios = tty_std_termios;
- xeno_console_driver.flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_NO_DEVFS;
- xeno_console_driver.refcount = &xeno_console_refcount;
- xeno_console_driver.table = xeno_console_table;
- xeno_console_driver.termios = xeno_console_termios;
- xeno_console_driver.termios_locked = xeno_console_termios_locked;
- /* Functions */
- xeno_console_driver.open = xeno_console_open;
- xeno_console_driver.close = xeno_console_close;
- xeno_console_driver.write = xeno_console_write;
- xeno_console_driver.write_room = xeno_console_write_room;
- xeno_console_driver.put_char = xeno_console_put_char;
- xeno_console_driver.chars_in_buffer = xeno_console_chars_in_buffer;
-
- if ( tty_register_driver(&xeno_console_driver) )
- {
- printk(KERN_ERR "Couldn't register Xeno console driver\n");
- }
- else
- {
- printk("Xeno console successfully installed\n");
- }
-
- return 0;
-}
-
-void __exit xeno_con_fini(void)
-{
- int ret;
-
- ret = tty_unregister_driver(&xeno_console_driver);
- if ( ret != 0 )
- {
- printk(KERN_ERR "Unable to unregister Xeno console driver: %d\n", ret);
- }
-}
-
-module_init(xeno_con_init);
-module_exit(xeno_con_fini);
-
+++ /dev/null
-O_TARGET := dom0.o
-obj-y := dom0_memory.o dom0_core.o vfr.o sched_ops.o
-include $(TOPDIR)/Rules.make
+++ /dev/null
-/*
- * domain 0 block driver interface
- *
- */
-
-#include <linux/config.h>
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-
-static int __init init_module(void)
-{
- request_module("xl_block");
- printk("Successfully installed domain 0 block interface\n");
-
-
- return 0;
-}
-
-static void __exit cleanup_module(void)
-{
- printk("Successfully de-installed domain-0 block interface\n");
- return 0;
-}
-
-module_init(init_module);
-module_exit(cleanup_module);
+++ /dev/null
-/******************************************************************************
- * dom0_core.c
- *
- * Interface to privileged domain-0 commands.
- *
- * Copyright (c) 2002, K A Fraser, B Dragovic
- */
-
-#include <linux/config.h>
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/slab.h>
-#include <linux/string.h>
-#include <linux/errno.h>
-#include <linux/proc_fs.h>
-
-#include <linux/mm.h>
-#include <linux/mman.h>
-#include <linux/swap.h>
-#include <linux/smp_lock.h>
-#include <linux/swapctl.h>
-#include <linux/iobuf.h>
-#include <linux/highmem.h>
-#include <linux/pagemap.h>
-#include <linux/seq_file.h>
-
-#include <asm/pgalloc.h>
-#include <asm/pgtable.h>
-#include <asm/uaccess.h>
-#include <asm/tlb.h>
-
-#include "dom0_ops.h"
-
-#define TRUE 1
-#define FALSE 0
-
-/* Private proc-file data structures. */
-typedef struct proc_data {
- unsigned int domain;
- unsigned long map_size;
-} dom_procdata_t;
-
-typedef struct proc_mem_data {
- unsigned long pfn;
- int tot_pages;
-} proc_memdata_t;
-
-#define XENO_BASE "xeno"
-#define DOM0_CMD_INTF "dom0_cmd"
-#define DOM0_NEWDOM "new_dom_data"
-#define DOM_LIST_INTF "domains"
-
-#define MAX_LEN 16
-#define DOM_DIR "dom"
-#define DOM_MEM "mem"
-#define DOM_VIF "vif"
-#define DOM_USAGE "usage"
-
-#define MAP_DISCONT 1
-
-struct proc_dir_entry *xeno_base;
-static struct proc_dir_entry *dom0_cmd_intf;
-static struct proc_dir_entry *proc_ft;
-static struct proc_dir_entry *dom_list_intf;
-
-unsigned long direct_mmap(unsigned long, unsigned long, pgprot_t, int, int);
-int direct_unmap(unsigned long, unsigned long);
-int direct_disc_unmap(unsigned long, unsigned long, int);
-
-static unsigned char readbuf[1204];
-
-static int cmd_read_proc(char *page, char **start, off_t off,
- int count, int *eof, void *data)
-{
- strcpy(page, readbuf);
- *readbuf = '\0';
- *eof = 1;
- *start = page;
- return strlen(page);
-}
-
-static ssize_t dom_vif_read(struct file * file, char * buff, size_t size, loff_t * off)
-{
- int hyp_buf[32];
- char buf[128];
- network_op_t op;
- static int finished = 0;
-
- if ( finished )
- {
- finished = 0;
- return 0;
- }
-
- op.cmd = NETWORK_OP_VIFQUERY;
- op.u.vif_query.domain = (unsigned int)
- ((struct proc_dir_entry *)file->f_dentry->d_inode->u.generic_ip)->data;
- op.u.vif_query.buf = hyp_buf;
-
- (void) HYPERVISOR_network_op(&op);
-
- if(hyp_buf[0] < 0) {
- strcpy(buf, "Error getting domain's vif list from hypervisor.\n");
- } else {
- int i;
- int len = 0;
- strcpy(buf, "No vif found");
-
- for(i = 1; i <= hyp_buf[0] && len < 127; i++)
- len += snprintf(buf + len, 127 - len, "%d\n", hyp_buf[i]);
- }
-
- if (*off >= (strlen(buf)+1)) return 0;
-
- copy_to_user(buff, buf, strlen(buf));
-
- finished = 1;
-
- return strlen(buf)+1;
-}
-
-struct file_operations dom_vif_ops = {
- read: dom_vif_read
-};
-
-static ssize_t dom_usage_read(struct file * file, char * buff, size_t size, loff_t * off)
-{
- char str[256];
- int vifs[32];
- dom0_op_t op;
- network_op_t netop;
- int i, end;
- unsigned int domain;
- static int finished = 0;
-
- if ( finished )
- {
- finished = 0;
- return 0;
- }
-
- domain = (unsigned int)
- ((struct proc_dir_entry *)file->f_dentry->d_inode->u.generic_ip)->data;
- op.cmd = DOM0_GETDOMAININFO;
-
- op.u.getdominfo.domain = domain;
-
- (void) HYPERVISOR_dom0_op(&op);
-
- end = snprintf(str, 256, "cpu: %lld\n", op.u.getdominfo.cpu_time);
-
- netop.cmd = NETWORK_OP_VIFQUERY;
- netop.u.vif_query.domain = domain;
- netop.u.vif_query.buf = vifs;
-
- (void) HYPERVISOR_network_op(&netop);
-
- for(i = 1; i <= vifs[0]; i++) {
- netop.cmd = NETWORK_OP_VIFGETINFO;
- netop.u.vif_getinfo.domain = domain;
- netop.u.vif_getinfo.vif = vifs[i];
-
- (void) HYPERVISOR_network_op(&netop);
-
- end += snprintf(str + end, 255 - end,
- "vif%d: sent %lld bytes (%lld packets) "
- "received %lld bytes (%lld packets)\n",
- vifs[i],
- netop.u.vif_getinfo.total_bytes_sent,
- netop.u.vif_getinfo.total_packets_sent,
- netop.u.vif_getinfo.total_bytes_received,
- netop.u.vif_getinfo.total_packets_received);
- }
-
- if (*off >= end + 1) return 0;
-
- copy_to_user(buff, str, end);
-
- finished = 1;
-
- return end + 1;
-}
-
-struct file_operations dom_usage_ops = {
- read: dom_usage_read
-};
-
-
-static void create_proc_dom_entries(int dom)
-{
- struct proc_dir_entry * dir;
- dom_procdata_t * dom_data;
- char dir_name[MAX_LEN];
- struct proc_dir_entry * file;
-
- snprintf(dir_name, MAX_LEN, "%s%d", DOM_DIR, dom);
-
- dom_data = (dom_procdata_t *)kmalloc(sizeof(dom_procdata_t), GFP_KERNEL);
- dom_data->domain = dom;
-
- dir = proc_mkdir(dir_name, xeno_base);
- dir->data = dom_data;
-
- file = create_proc_entry(DOM_VIF, 0600, dir);
- if (file != NULL)
- {
- file->owner = THIS_MODULE;
- file->nlink = 1;
- file->proc_fops = &dom_vif_ops;
- file->data = (void *) dom;
- }
-
- file = create_proc_entry(DOM_USAGE, 0600, dir);
- if (file != NULL)
- {
- file->owner = THIS_MODULE;
- file->nlink = 1;
- file->proc_fops = &dom_usage_ops;
- file->data = (void *) dom;
- }
-}
-
-static ssize_t dom_mem_write(struct file * file, const char * buff,
- size_t size , loff_t * off)
-{
- dom_mem_t mem_data;
-
- copy_from_user(&mem_data, (dom_mem_t *)buff, sizeof(dom_mem_t));
-
- if(direct_disc_unmap(mem_data.vaddr, mem_data.start_pfn,
- mem_data.tot_pages) == 0){
- return sizeof(sizeof(dom_mem_t));
- } else {
- return -1;
- }
-}
-
-static ssize_t dom_mem_read(struct file * file, char * buff, size_t size, loff_t * off)
-{
- unsigned long addr;
- pgprot_t prot;
-
- proc_memdata_t * mem_data = (proc_memdata_t *)((struct proc_dir_entry *)file->f_dentry->d_inode->u.generic_ip)->data;
-
- prot = PAGE_SHARED;
-
- /* remap the range using xen specific routines */
-
- addr = direct_mmap(mem_data->pfn << PAGE_SHIFT, mem_data->tot_pages << PAGE_SHIFT, prot, MAP_DISCONT, mem_data->tot_pages);
-
- copy_to_user((unsigned long *)buff, &addr, sizeof(addr));
-
- return sizeof(addr);
-}
-
-struct file_operations dom_mem_ops = {
- read: dom_mem_read,
- write: dom_mem_write,
-};
-
-static int dom_map_mem(unsigned int dom, unsigned long pfn, int tot_pages)
-{
- int ret = -ENOENT;
- struct proc_dir_entry * pd = xeno_base->subdir;
- struct proc_dir_entry * file;
- proc_memdata_t * memdata;
-
- while(pd != NULL){
-
- if((pd->mode & S_IFDIR) && ((dom_procdata_t *)pd->data)->domain == dom){
-
- /* check if there is already an entry for mem and if so
- * remove it.
- */
- remove_proc_entry(DOM_MEM, pd);
-
- /* create new entry with parameters describing what to do
- * when it is mmaped.
- */
- file = create_proc_entry(DOM_MEM, 0600, pd);
- if(file != NULL)
- {
- file->owner = THIS_MODULE;
- file->nlink = 1;
- file->proc_fops = &dom_mem_ops;
-
- memdata = (proc_memdata_t *)kmalloc(sizeof(proc_memdata_t), GFP_KERNEL);
- memdata->pfn = pfn;
- memdata->tot_pages = tot_pages;
- file->data = memdata;
-
- ret = 0;
- break;
- }
-
- ret = -EAGAIN;
- break;
- }
- pd = pd->next;
- }
-
- return ret;
-}
-
-/* function used to retrieve data associated with new domain */
-static ssize_t dom_data_read(struct file * file, char * buff, size_t size, loff_t * off)
-{
- dom0_newdomain_t * dom_data = (dom0_newdomain_t *)
- ((struct proc_dir_entry *)file->f_dentry->d_inode->u.generic_ip)->data;
-
- copy_to_user((dom0_newdomain_t *)buff, dom_data, sizeof(dom0_newdomain_t));
-
- remove_proc_entry(DOM0_NEWDOM, xeno_base);
-
- kfree(dom_data);
-
- return sizeof(dom0_newdomain_t);
-}
-
-struct file_operations newdom_data_fops = {
- read: dom_data_read,
-};
-
-static int cmd_write_proc(struct file *file, const char *buffer,
- u_long count, void *data)
-{
- dom0_op_t op;
- int ret = 0;
- struct proc_dir_entry * new_dom_id;
- dom0_newdomain_t * params;
- int i;
- unsigned long p;
-
- copy_from_user(&op, buffer, sizeof(dom0_op_t));
-
- /* do some sanity checks */
- if(op.cmd > MAX_CMD){
- ret = -ENOSYS;
- goto out;
- }
-
- if ( op.cmd == MAP_DOM_MEM )
- {
- ret = dom_map_mem(op.u.dommem.domain, op.u.dommem.start_pfn,
- op.u.dommem.tot_pages);
- }
- else if ( op.cmd == DO_PGUPDATES )
- {
- ret = HYPERVISOR_pt_update(op.u.pgupdate.pgt_update_arr,
- op.u.pgupdate.num_pgt_updates);
- }
- else
- {
- ret = HYPERVISOR_dom0_op(&op);
-
- /* if new domain created, create proc entries */
- if(op.cmd == DOM0_CREATEDOMAIN) {
- create_proc_dom_entries(ret);
-
- params = (dom0_newdomain_t *)kmalloc(sizeof(dom0_newdomain_t),
- GFP_KERNEL);
- params->memory_kb = op.u.newdomain.memory_kb;
- params->pg_head = op.u.newdomain.pg_head;
- params->num_vifs = op.u.newdomain.num_vifs;
- params->domain = op.u.newdomain.domain;
-
- /* now notify user space of the new domain's id */
- new_dom_id = create_proc_entry(DOM0_NEWDOM, 0600, xeno_base);
- if ( new_dom_id != NULL )
- {
- new_dom_id->owner = THIS_MODULE;
- new_dom_id->nlink = 1;
- new_dom_id->proc_fops = &newdom_data_fops;
- new_dom_id->data = (void *)params;
- }
-
- }
-
- }
-
-out:
- return ret;
-
-}
-
-/***********************************************************************
- *
- * Implementation of /proc/xeno/domains
- */
-
-static dom0_op_t proc_domains_op;
-static int proc_domains_finished;
-static rwlock_t proc_xeno_domains_lock = RW_LOCK_UNLOCKED;
-
-static void *xeno_domains_next(struct seq_file *s, void *v, loff_t *pos)
-{
- int ret;
-
- if (pos != NULL) { ++ (*pos); }
- if (!proc_domains_finished) {
- proc_domains_op.u.getdominfo.domain ++;
- ret = HYPERVISOR_dom0_op(&proc_domains_op);
- if (ret < 0) proc_domains_finished = TRUE;
- }
-
- return (proc_domains_finished) ? NULL : &proc_domains_op;
-}
-
-static void *xeno_domains_start(struct seq_file *s, loff_t *ppos)
-{
- loff_t pos = *ppos;
-
- write_lock (&proc_xeno_domains_lock);
- proc_domains_op.cmd = DOM0_GETDOMAININFO;
- proc_domains_op.u.getdominfo.domain = 0;
- (void)HYPERVISOR_dom0_op(&proc_domains_op);
- proc_domains_finished = FALSE;
-
- while (pos > 0) {
- pos --;
- xeno_domains_next (s, NULL, NULL);
- }
-
- return (proc_domains_finished) ? NULL : &proc_domains_op;
-}
-
-static void xeno_domains_stop(struct seq_file *s, void *v)
-{
- write_unlock (&proc_xeno_domains_lock);
-}
-
-static int xeno_domains_show(struct seq_file *s, void *v)
-{
- dom0_op_t *di = v;
-
- /*
- * Output one domain's details to dom0.
- *
- * If you update this format string then change xi_list to match.
- */
-
- seq_printf (s,
- "%8d %2d %1d %2d %8d %8ld %p %8d %s\n",
- di -> u.getdominfo.domain,
- di -> u.getdominfo.processor,
- di -> u.getdominfo.has_cpu,
- di -> u.getdominfo.state,
- di -> u.getdominfo.hyp_events,
- di -> u.getdominfo.mcu_advance,
- di -> u.getdominfo.pg_head,
- di -> u.getdominfo.tot_pages,
- di -> u.getdominfo.name);
-
- return 0;
-}
-
-struct seq_operations xeno_domains_op = {
- .start = xeno_domains_start,
- .next = xeno_domains_next,
- .stop = xeno_domains_stop,
- .show = xeno_domains_show,
-};
-
-static int xeno_domains_open(struct inode *inode, struct file *file)
-{
- return seq_open(file, &xeno_domains_op);
-}
-
-static struct file_operations proc_xeno_domains_operations = {
- open: xeno_domains_open,
- read: seq_read,
- llseek: seq_lseek,
- release: seq_release,
-};
-
-/***********************************************************************/
-
-
-
-static int __init init_module(void)
-{
- /* xeno proc root setup */
- xeno_base = proc_mkdir(XENO_BASE, &proc_root);
-
- /* xeno control interface */
- *readbuf = '\0';
- dom0_cmd_intf = create_proc_entry (DOM0_CMD_INTF, 0600, xeno_base);
- if ( dom0_cmd_intf != NULL )
- {
- dom0_cmd_intf->owner = THIS_MODULE;
- dom0_cmd_intf->nlink = 1;
- dom0_cmd_intf->read_proc = cmd_read_proc;
- dom0_cmd_intf->write_proc = cmd_write_proc;
- }
-
- /* domain list interface */
- dom_list_intf = create_proc_entry (DOM_LIST_INTF, 0400, xeno_base);
- if ( dom_list_intf != NULL )
- {
- dom_list_intf -> owner = THIS_MODULE;
- dom_list_intf -> nlink = 1;
- dom_list_intf -> proc_fops = &proc_xeno_domains_operations;
- }
-
- /* set up /proc entries for dom 0 */
- create_proc_dom_entries(0);
-
- return 0;
-}
-
-
-static void __exit cleanup_module(void)
-{
- if ( dom0_cmd_intf == NULL ) return;
- remove_proc_entry("dom0", &proc_root);
- dom0_cmd_intf = NULL;
-}
-
-
-module_init(init_module);
-module_exit(cleanup_module);
+++ /dev/null
-#include <linux/slab.h>
-#include <linux/mm.h>
-#include <linux/mman.h>
-#include <linux/swap.h>
-#include <linux/smp_lock.h>
-#include <linux/swapctl.h>
-#include <linux/iobuf.h>
-#include <linux/highmem.h>
-#include <linux/pagemap.h>
-#include <linux/list.h>
-
-#include <asm/pgalloc.h>
-#include <asm/uaccess.h>
-#include <asm/tlb.h>
-#include <asm/mmu.h>
-
-#include "dom0_ops.h"
-
-#define MAP_CONT 0
-#define MAP_DISCONT 1
-
-extern struct list_head * find_direct(struct list_head *, unsigned long);
-
-/*
- * bd240: functions below perform direct mapping to the real physical pages
- * needed for mapping various hypervisor specific structures needed in dom0
- * userspace by various management applications such as domain builder etc.
- */
-
-#define direct_set_pte(pteptr, pteval) queue_l1_entry_update(__pa(pteptr)|PGREQ_UNCHECKED_UPDATE, (pteval).pte_low)
-
-#define direct_pte_clear(pteptr) queue_l1_entry_update(__pa(pteptr)|PGREQ_UNCHECKED_UPDATE, 0)
-
-#define __direct_pte(x) ((pte_t) { (x) } )
-#define __direct_mk_pte(page_nr,pgprot) __direct_pte(((page_nr) << PAGE_SHIFT) | pgprot_val(pgprot))
-#define direct_mk_pte_phys(physpage, pgprot) __direct_mk_pte((physpage) >> PAGE_SHIFT, pgprot)
-
-static inline void forget_pte(pte_t page)
-{
- if (!pte_none(page)) {
- printk("forget_pte: old mapping existed!\n");
- BUG();
- }
-}
-
-static inline void direct_remappte_range(pte_t * pte, unsigned long address, unsigned long size,
- unsigned long phys_addr, pgprot_t prot)
-{
- unsigned long end;
-
- address &= ~PMD_MASK;
- end = address + size;
- if (end > PMD_SIZE)
- end = PMD_SIZE;
- do {
- pte_t oldpage;
- oldpage = ptep_get_and_clear(pte);
-
- direct_set_pte(pte, direct_mk_pte_phys(phys_addr, prot));
-
- forget_pte(oldpage);
- address += PAGE_SIZE;
- phys_addr += PAGE_SIZE;
- pte++;
- } while (address && (address < end));
-
-}
-
-static inline int direct_remappmd_range(struct mm_struct *mm, pmd_t * pmd, unsigned long address, unsigned long size,
- unsigned long phys_addr, pgprot_t prot)
-{
- unsigned long end;
-
- address &= ~PGDIR_MASK;
- end = address + size;
- if (end > PGDIR_SIZE)
- end = PGDIR_SIZE;
- phys_addr -= address;
- do {
- pte_t * pte = pte_alloc(mm, pmd, address);
- if (!pte)
- return -ENOMEM;
- direct_remappte_range(pte, address, end - address, address + phys_addr, prot);
- address = (address + PMD_SIZE) & PMD_MASK;
- pmd++;
- } while (address && (address < end));
- return 0;
-}
-
-/* Note: this is only safe if the mm semaphore is held when called. */
-int direct_remap_page_range(unsigned long from, unsigned long phys_addr, unsigned long size, pgprot_t prot)
-{
- int error = 0;
- pgd_t * dir;
- unsigned long beg = from;
- unsigned long end = from + size;
- struct mm_struct *mm = current->mm;
-
- phys_addr -= from;
- dir = pgd_offset(mm, from);
- flush_cache_range(mm, beg, end);
- if (from >= end)
- BUG();
-
- spin_lock(&mm->page_table_lock);
- do {
- pmd_t *pmd = pmd_alloc(mm, dir, from);
- error = -ENOMEM;
- if (!pmd)
- break;
- error = direct_remappmd_range(mm, pmd, from, end - from, phys_addr + from, prot);
- if (error)
- break;
- from = (from + PGDIR_SIZE) & PGDIR_MASK;
- dir++;
- } while (from && (from < end));
- spin_unlock(&mm->page_table_lock);
- flush_tlb_range(mm, beg, end);
- return error;
-}
-
-/*
- * used for remapping discontiguous bits of domain's memory, pages to map are
- * found from frame table beginning at the given first_pg index
- */
-int direct_remap_disc_page_range(unsigned long from,
- unsigned long first_pg, int tot_pages, pgprot_t prot)
-{
- dom0_op_t dom0_op;
- unsigned long *pfns = get_free_page(GFP_KERNEL);
- unsigned long start = from;
- int pages, i;
-
- while ( tot_pages != 0 )
- {
- dom0_op.cmd = DOM0_GETMEMLIST;
- dom0_op.u.getmemlist.start_pfn = first_pg;
- pages = 1023;
- dom0_op.u.getmemlist.num_pfns = 1024;
- if ( tot_pages < 1024 )
- dom0_op.u.getmemlist.num_pfns = pages = tot_pages;
- dom0_op.u.getmemlist.buffer = pfns;
- (void)HYPERVISOR_dom0_op(&dom0_op);
- first_pg = pfns[1023];
-
- for ( i = 0; i < pages; i++ )
- {
- if(direct_remap_page_range(start, pfns[i] << PAGE_SHIFT,
- PAGE_SIZE, prot))
- goto out;
- start += PAGE_SIZE;
- tot_pages--;
- }
- }
-
-out:
- free_page(pfns);
- return tot_pages;
-}
-
-/* below functions replace standard sys_mmap and sys_munmap which are absolutely useless
- * for direct memory mapping. direct_zap* functions are minor ammendments to the
- * original versions in mm/memory.c. the changes are to enable unmapping of real physical
- * addresses.
- */
-
-unsigned long direct_mmap(unsigned long phys_addr, unsigned long size,
- pgprot_t prot, int flag, int tot_pages)
-{
- direct_mmap_node_t * dmmap;
- struct list_head * entry;
- unsigned long addr;
- int ret = 0;
-
- if(!capable(CAP_SYS_ADMIN)){
- ret = -EPERM;
- goto out;
- }
-
- /* get unmapped area invokes xen specific arch_get_unmapped_area */
- addr = get_unmapped_area(NULL, 0, size, 0, 0);
- if(addr & ~PAGE_MASK){
- ret = -ENOMEM;
- goto out;
- }
-
- /* add node on the list of directly mapped areas, make sure the
- * list remains sorted.
- */
- dmmap = (direct_mmap_node_t *)kmalloc(sizeof(direct_mmap_node_t), GFP_KERNEL);
- dmmap->vm_start = addr;
- dmmap->vm_end = addr + size;
- entry = find_direct(¤t->mm->context.direct_list, addr);
- if(entry != ¤t->mm->context.direct_list){
- list_add_tail(&dmmap->list, entry);
- } else {
- list_add_tail(&dmmap->list, ¤t->mm->context.direct_list);
- }
-
- /* and perform the mapping */
- if(flag == MAP_DISCONT){
- ret = direct_remap_disc_page_range(addr, phys_addr >> PAGE_SHIFT,
- tot_pages, prot);
- } else {
- ret = direct_remap_page_range(addr, phys_addr, size, prot);
- }
-
- if(ret == 0)
- ret = addr;
-
-out:
- return ret;
-}
-
-/* most of the checks, refcnt updates, cache stuff have been thrown out as they are not
- * needed
- */
-static inline int direct_zap_pte_range(mmu_gather_t *tlb, pmd_t * pmd, unsigned long address,
- unsigned long size)
-{
- unsigned long offset;
- pte_t * ptep;
- int freed = 0;
-
- if (pmd_none(*pmd))
- return 0;
- if (pmd_bad(*pmd)) {
- pmd_ERROR(*pmd);
- pmd_clear(pmd);
- return 0;
- }
- ptep = pte_offset(pmd, address);
- offset = address & ~PMD_MASK;
- if (offset + size > PMD_SIZE)
- size = PMD_SIZE - offset;
- size &= PAGE_MASK;
- for (offset=0; offset < size; ptep++, offset += PAGE_SIZE) {
- pte_t pte = *ptep;
- if (pte_none(pte))
- continue;
- freed ++;
- direct_pte_clear(ptep);
- }
-
- return freed;
-}
-
-static inline int direct_zap_pmd_range(mmu_gather_t *tlb, pgd_t * dir,
- unsigned long address, unsigned long size)
-{
- pmd_t * pmd;
- unsigned long end;
- int freed;
-
- if (pgd_none(*dir))
- return 0;
- if (pgd_bad(*dir)) {
- pgd_ERROR(*dir);
- pgd_clear(dir);
- return 0;
- }
- pmd = pmd_offset(dir, address);
- end = address + size;
- if (end > ((address + PGDIR_SIZE) & PGDIR_MASK))
- end = ((address + PGDIR_SIZE) & PGDIR_MASK);
- freed = 0;
- do {
- freed += direct_zap_pte_range(tlb, pmd, address, end - address);
- address = (address + PMD_SIZE) & PMD_MASK;
- pmd++;
- } while (address < end);
- return freed;
-}
-
-/*
- * remove user pages in a given range.
- */
-void direct_zap_page_range(struct mm_struct *mm, unsigned long address, unsigned long size)
-{
- mmu_gather_t *tlb;
- pgd_t * dir;
- unsigned long start = address, end = address + size;
- int freed = 0;
-
- dir = pgd_offset(mm, address);
-
- /*
- * This is a long-lived spinlock. That's fine.
- * There's no contention, because the page table
- * lock only protects against kswapd anyway, and
- * even if kswapd happened to be looking at this
- * process we _want_ it to get stuck.
- */
- if (address >= end)
- BUG();
- spin_lock(&mm->page_table_lock);
- flush_cache_range(mm, address, end);
- tlb = tlb_gather_mmu(mm);
-
- do {
- freed += direct_zap_pmd_range(tlb, dir, address, end - address);
- address = (address + PGDIR_SIZE) & PGDIR_MASK;
- dir++;
- } while (address && (address < end));
-
- /* this will flush any remaining tlb entries */
- tlb_finish_mmu(tlb, start, end);
-
- /* decrementing rss removed */
-
- spin_unlock(&mm->page_table_lock);
-}
-
-int direct_unmap(unsigned long addr, unsigned long size)
-{
- direct_mmap_node_t * node;
- struct list_head * curr;
- struct list_head * direct_list = ¤t->mm->context.direct_list;
-
- curr = direct_list->next;
- while(curr != direct_list){
- node = list_entry(curr, direct_mmap_node_t, list);
- if(node->vm_start == addr)
- break;
- curr = curr->next;
- }
-
- if(curr == direct_list)
- return -1;
-
- list_del(&node->list);
- kfree(node);
-
- direct_zap_page_range(current->mm, addr, size);
-
- return 0;
-}
-
-int direct_disc_unmap(unsigned long from, unsigned long first_pg, int tot_pages)
-{
- int count = 0;
- direct_mmap_node_t * node;
- struct list_head * curr;
- struct list_head * direct_list = ¤t->mm->context.direct_list;
-
- curr = direct_list->next;
- while(curr != direct_list){
- node = list_entry(curr, direct_mmap_node_t, list);
-
- if(node->vm_start == from)
- break;
- curr = curr->next;
- }
-
- if(curr == direct_list)
- return -1;
-
- list_del(&node->list);
- kfree(node);
-
- while(count < tot_pages){
- direct_zap_page_range(current->mm, from, PAGE_SIZE);
- from += PAGE_SIZE;
- count++;
- }
-
- return 0;
-}
+++ /dev/null
-/******************************************************************************
- * dom0_ops.h
- *
- * Process command requests from domain-0 guest OS.
- * This file includes the Xen part of the interface, plus the extra stuff
- * that is dealt with by Xenolinux without being handed down to Xen.
- *
- * Copyright (c) 2002-2003, K A Fraser, B Dragovic
- */
-
-#ifndef __DOM0_DOM0_OPS_H__
-#define __DOM0_DOM0_OPS_H__
-
-/* External users of this header file will include Xen's version separately. */
-#ifdef __KERNEL__
-#define NO_DOM0_OP_T
-#include <asm/hypervisor-ifs/dom0_ops.h>
-#endif
-
-/* Extra commands dealt with by Xenolinux. */
-#define MAP_DOM_MEM 14
-#define DO_PGUPDATES 15
-#define MAX_CMD 16
-
-typedef struct dom_mem
-{
- unsigned int domain;
- unsigned long vaddr;
- unsigned long start_pfn;
- int tot_pages;
-} dom_mem_t;
-
-typedef struct dom_pgupdate
-{
- unsigned long pgt_update_arr;
- unsigned long num_pgt_updates;
-} dom_pgupdate_t;
-
-typedef struct dom0_op_st
-{
- unsigned long cmd;
- union
- {
- dom0_newdomain_t newdomain;
- dom0_killdomain_t killdomain;
- dom0_getmemlist_t getmemlist;
- dom0_bvtctl_t bvtctl;
- dom0_adjustdom_t adjustdom;
- dom_mem_t dommem;
- dom_pgupdate_t pgupdate;
- dom_meminfo_t meminfo;
- dom0_getdominfo_t getdominfo;
- }
- u;
-} dom0_op_t;
-
-#endif /* __DOM0_DOM0_OPS_H__ */
+++ /dev/null
-/* -*- Mode:C; c-basic-offset:4; tab-width:4 -*-
- ****************************************************************************
- * (C) 2003 - Rolf Neugebauer - Intel Research Cambridge
- ****************************************************************************
- *
- * File: sched_ops.c
- * Author: Rolf Neugebauer (neugebar@dcs.gla.ac.uk)
- * Changes:
- *
- * Date: Mar 2003
- *
- * Environment: XenoLinux
- * Description: Dom0 Control interface to scheduler in Xen
- *
- * code based on Andy's vfr parsing code
- *
- * Commands understood by the interface:
- *
- * C <context swith allowance>
- * S <did> <mcu advance> <warp> <warp limit> <unwarp limit>
- *
- ****************************************************************************
- * $Id: c-insert.c,v 1.7 2002/11/08 16:04:34 rn Exp $
- ****************************************************************************
- */
-
-#include <linux/config.h>
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/ctype.h>
-#include <linux/string.h>
-#include <linux/errno.h>
-#include <linux/proc_fs.h>
-
-#include "dom0_ops.h"
-
-#define SCHED_ENTRY "sched"
-extern struct proc_dir_entry *xeno_base;
-static struct proc_dir_entry *sched_pde;
-
-static unsigned char readbuf[1024];
-
-static int sched_read_proc(char *page, char **start, off_t off,
- int count, int *eof, void *data)
-{
- strcpy(page, readbuf);
- *readbuf = '\0';
- *eof = 1;
- *start = page;
- return strlen(page);
-}
-
-
-static int sched_write_proc(struct file *file, const char *buffer,
- u_long count, void *data)
-{
- dom0_op_t op;
-
- int ret, len;
- int ts, te, tl; /* token start, end, and length */
-
- /* Only admin can adjust scheduling parameters */
- if ( !capable(CAP_SYS_ADMIN) )
- return -EPERM;
-
- /* parse the commands */
- len = count;
- ts = te = 0;
-
- while ( count && isspace(buffer[ts]) ) { ts++; count--; } /*skip spaces*/
- te = ts;
- while ( count && !isspace(buffer[te]) ) { te++; count--; } /*command end*/
- if ( te <= ts ) goto bad;
- tl = te - ts;
-
- if ( strncmp(&buffer[ts], "C", tl) == 0 ) {
- op.cmd = DOM0_BVTCTL;
- } else if ( strncmp(&buffer[ts], "S", tl) == 0 ) {
- op.cmd = DOM0_ADJUSTDOM;
- } else
- goto bad;
-
- /* skip whitspaces and get first parameter */
- ts = te; while ( count && isspace(buffer[ts]) ) { ts++; count--; }
- te = ts; while ( count && !isspace(buffer[te]) ) { te++; count--; }
- if ( te <= ts ) goto bad;
- tl = te - ts;
- if ( !isdigit(buffer[ts]) ) goto bad;
-
- if (op.cmd == DOM0_BVTCTL) {
- /* get context switch allowance */
- sscanf(&buffer[ts], "%lu", &op.u.bvtctl.ctx_allow);
- } else if (op.cmd == DOM0_ADJUSTDOM) {
- sscanf(&buffer[ts], "%u %lu %lu %lu %lu",
- &op.u.adjustdom.domain,
- &op.u.adjustdom.mcu_adv,
- &op.u.adjustdom.warp,
- &op.u.adjustdom.warpl,
- &op.u.adjustdom.warpu);
- }
- ret = HYPERVISOR_dom0_op(&op);
- return sizeof(op);
-
- bad:
- return -EINVAL;
-
-}
-
-
-/*
- * main scheduler interface driver driver initialization function.
- */
-static int __init init_module(void)
-{
- printk(KERN_ALERT "Starting Domain Scheduler Control Interface\n");
-
- sched_pde = create_proc_entry(SCHED_ENTRY, 0600, xeno_base);
- if ( sched_pde == NULL )
- {
- printk(KERN_ALERT "Unable to create dom scheduler proc entry!");
- return -1;
- }
-
- sched_pde->read_proc = sched_read_proc;
- sched_pde->write_proc = sched_write_proc;
-
- return 0;
-}
-
-static void __exit cleanup_module(void)
-{
-}
-
-module_init(init_module);
-module_exit(cleanup_module);
-
+++ /dev/null
-/******************************************************************************
- * vfr.c
- *
- * Interface to the virtual firewall/router.
- *
- */
-
-#include <linux/config.h>
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/slab.h>
-#include <linux/string.h>
-#include <linux/errno.h>
-#include <linux/proc_fs.h>
-
-#include <asm/hypervisor-ifs/network.h>
-
-static struct proc_dir_entry *proc_vfr;
-
-static unsigned char readbuf[1024];
-
-/* Helpers, implemented at the bottom. */
-u32 getipaddr(const char *buff, unsigned int len);
-u16 antous(const char *buff, int len);
-int anton(const char *buff, int len);
-
-static int vfr_read_proc(char *page, char **start, off_t off,
- int count, int *eof, void *data)
-{
- strcpy(page, readbuf);
- *readbuf = '\0';
- *eof = 1;
- *start = page;
- return strlen(page);
-}
-
-/* The format for the vfr interface is as follows:
- *
- * COMMAND <field>=<val> [<field>=<val> [...]]
- *
- * where:
- *
- * COMMAND = { ACCEPT | COUNT }
- *
- * field=val pairs are as follows:
- *
- * field = { srcaddr | dstaddr }
- * val is a dot seperated, numeric IP address.
- *
- * field = { srcport | dstport }
- * val is a (16-bit) unsigned int
- *
- * field = { proto }
- * val = { IP | TCP | UDP | ARP }
- *
- */
-
-#define isspace(_x) ( ((_x)==' ') || ((_x)=='\t') || ((_x)=='\v') || \
- ((_x)=='\f') || ((_x)=='\r') || ((_x)=='\n') )
-
-static int vfr_write_proc(struct file *file, const char *buffer,
- u_long count, void *data)
-{
- network_op_t op;
- int ret, len;
- int ts, te, tl; // token start, end, and length
- int fs, fe, fl; // field.
-
- len = count;
- ts = te = 0;
-
- memset(&op, 0, sizeof(network_op_t));
-
- // get the command:
- while ( count && isspace(buffer[ts]) ) { ts++; count--; } // skip spaces.
- te = ts;
- while ( count && !isspace(buffer[te]) ) { te++; count--; } // command end
- if ( te <= ts ) goto bad;
- tl = te - ts;
-
- if ( strncmp(&buffer[ts], "ADD", tl) == 0 )
- {
- op.cmd = NETWORK_OP_ADDRULE;
- }
- else if ( strncmp(&buffer[ts], "DELETE", tl) == 0 )
- {
- op.cmd = NETWORK_OP_DELETERULE;
- }
- else if ( strncmp(&buffer[ts], "PRINT", tl) == 0 )
- {
- op.cmd = NETWORK_OP_GETRULELIST;
- goto doneparsing;
- }
-
- ts = te;
-
- // get the action
- while ( count && (buffer[ts] == ' ') ) { ts++; count--; } // skip spaces.
- te = ts;
- while ( count && (buffer[te] != ' ') ) { te++; count--; } // command end
- if ( te <= ts ) goto bad;
- tl = te - ts;
-
- if ( strncmp(&buffer[ts], "ACCEPT", tl) == 0 )
- {
- op.u.net_rule.action = NETWORK_ACTION_ACCEPT;
- goto keyval;
- }
- if ( strncmp(&buffer[ts], "COUNT", tl) == 0 )
- {
- op.u.net_rule.action = NETWORK_ACTION_COUNT;
- goto keyval;
- }
-
- // default case;
- return (len);
-
-
- // get the key=val pairs.
- keyval:
- while (count)
- {
- //get field
- ts = te; while ( count && isspace(buffer[ts]) ) { ts++; count--; }
- te = ts;
- while ( count && !isspace(buffer[te]) && (buffer[te] != '=') )
- { te++; count--; }
- if ( te <= ts )
- goto doneparsing;
- tl = te - ts;
- fs = ts; fe = te; fl = tl; // save the field markers.
- // skip " = " (ignores extra equals.)
- while ( count && (isspace(buffer[te]) || (buffer[te] == '=')) )
- { te++; count--; }
- ts = te;
- while ( count && !isspace(buffer[te]) ) { te++; count--; }
- tl = te - ts;
-
- if ( (fl <= 0) || (tl <= 0) ) goto bad;
-
- /* NB. Prefix matches must go first! */
- if (strncmp(&buffer[fs], "src", fl) == 0)
- {
- op.u.net_rule.src_vif = VIF_ANY_INTERFACE;
- }
- else if (strncmp(&buffer[fs], "dst", fl) == 0)
- {
- op.u.net_rule.dst_vif = VIF_PHYSICAL_INTERFACE;
- }
- else if (strncmp(&buffer[fs], "srcaddr", fl) == 0)
- {
- op.u.net_rule.src_addr = getipaddr(&buffer[ts], tl);
- }
- else if (strncmp(&buffer[fs], "dstaddr", fl) == 0)
- {
- op.u.net_rule.dst_addr = getipaddr(&buffer[ts], tl);
- }
- else if (strncmp(&buffer[fs], "srcaddrmask", fl) == 0)
- {
- op.u.net_rule.src_addr_mask = getipaddr(&buffer[ts], tl);
- }
- else if (strncmp(&buffer[fs], "dstaddrmask", fl) == 0)
- {
- op.u.net_rule.dst_addr_mask = getipaddr(&buffer[ts], tl);
- }
- else if (strncmp(&buffer[fs], "srcport", fl) == 0)
- {
- op.u.net_rule.src_port = antous(&buffer[ts], tl);
- }
- else if (strncmp(&buffer[fs], "dstport", fl) == 0)
- {
- op.u.net_rule.dst_port = antous(&buffer[ts], tl);
- }
- else if (strncmp(&buffer[fs], "srcportmask", fl) == 0)
- {
- op.u.net_rule.src_port_mask = antous(&buffer[ts], tl);
- }
- else if (strncmp(&buffer[fs], "dstportmask", fl) == 0)
- {
- op.u.net_rule.dst_port_mask = antous(&buffer[ts], tl);
- }
- else if (strncmp(&buffer[fs], "srcdom", fl) == 0)
- {
- op.u.net_rule.src_vif |= anton(&buffer[ts], tl)<<VIF_DOMAIN_SHIFT;
- }
- else if (strncmp(&buffer[fs], "srcidx", fl) == 0)
- {
- op.u.net_rule.src_vif |= anton(&buffer[ts], tl);
- }
- else if (strncmp(&buffer[fs], "dstdom", fl) == 0)
- {
- op.u.net_rule.dst_vif |= anton(&buffer[ts], tl)<<VIF_DOMAIN_SHIFT;
- }
- else if (strncmp(&buffer[fs], "dstidx", fl) == 0)
- {
- op.u.net_rule.dst_vif |= anton(&buffer[ts], tl);
- }
- else if ( (strncmp(&buffer[fs], "proto", fl) == 0))
- {
- if (strncmp(&buffer[ts], "any", tl) == 0)
- op.u.net_rule.proto = NETWORK_PROTO_ANY;
- if (strncmp(&buffer[ts], "ip", tl) == 0)
- op.u.net_rule.proto = NETWORK_PROTO_IP;
- if (strncmp(&buffer[ts], "tcp", tl) == 0)
- op.u.net_rule.proto = NETWORK_PROTO_TCP;
- if (strncmp(&buffer[ts], "udp", tl) == 0)
- op.u.net_rule.proto = NETWORK_PROTO_UDP;
- if (strncmp(&buffer[ts], "arp", tl) == 0)
- op.u.net_rule.proto = NETWORK_PROTO_ARP;
- }
- }
-
- doneparsing:
- ret = HYPERVISOR_network_op(&op);
- return(len);
-
- bad:
- return(len);
-
-
-}
-
-static int __init init_module(void)
-{
- *readbuf = '\0';
- proc_vfr = create_proc_entry ("vfr", 0600, &proc_root);
- if ( proc_vfr != NULL )
- {
- proc_vfr->owner = THIS_MODULE;
- proc_vfr->nlink = 1;
- proc_vfr->read_proc = vfr_read_proc;
- proc_vfr->write_proc = vfr_write_proc;
- printk("Successfully installed virtual firewall/router interface\n");
- }
- return 0;
-}
-
-static void __exit cleanup_module(void)
-{
- if ( proc_vfr == NULL ) return;
- remove_proc_entry("vfr", &proc_root);
- proc_vfr = NULL;
-}
-
-module_init(init_module);
-module_exit(cleanup_module);
-
-/* Helper functions start here: */
-
-int anton(const char *buff, int len)
-{
- int ret;
- char c;
- int sign = 1;
-
- ret = 0;
-
- if (len == 0) return 0;
- if (*buff == '-') { sign = -1; buff++; len--; }
-
- while ( (len) && ((c = *buff) >= '0') && (c <= '9') )
- {
- ret *= 10;
- ret += c - '0';
- buff++; len--;
- }
-
- ret *= sign;
- return ret;
-}
-
-u16 antous(const char *buff, int len)
-{
- u16 ret;
- char c;
-
- ret = 0;
-
- while ( (len) && ((c = *buff) >= '0') && (c <= '9') )
- {
- ret *= 10;
- ret += c - '0';
- buff++; len--;
- }
-
- return ret;
-}
-
-u32 getipaddr(const char *buff, unsigned int len)
-{
- char c;
- u32 ret, val;
-
- ret = 0; val = 0;
-
- while ( len )
- {
- if (!((((c = *buff) >= '0') && ( c <= '9')) || ( c == '.' ) ) )
- {
- return(0); // malformed.
- }
-
- if ( c == '.' ) {
- if (val > 255) return (0); //malformed.
- ret = ret << 8;
- ret += val;
- val = 0;
- len--; buff++;
- continue;
- }
- val *= 10;
- val += c - '0';
- buff++; len--;
- }
- ret = ret << 8;
- ret += val;
-
- return (ret);
-}
-
+++ /dev/null
-O_TARGET := net.o
-obj-y := network.o
-include $(TOPDIR)/Rules.make
+++ /dev/null
-/******************************************************************************
- * network.c
- *
- * Virtual network driver for XenoLinux.
- *
- * Copyright (c) 2002-2003, K A Fraser
- */
-
-#include <linux/config.h>
-#include <linux/module.h>
-
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/slab.h>
-#include <linux/string.h>
-#include <linux/errno.h>
-
-#include <linux/netdevice.h>
-#include <linux/inetdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/skbuff.h>
-#include <linux/init.h>
-
-#include <asm/io.h>
-#include <net/sock.h>
-#include <net/pkt_sched.h>
-
-#define NET_TX_IRQ _EVENT_NET_TX
-#define NET_RX_IRQ _EVENT_NET_RX
-
-#define TX_MAX_ENTRIES (TX_RING_SIZE - 2)
-#define RX_MAX_ENTRIES (RX_RING_SIZE - 2)
-
-#define TX_RING_INC(_i) (((_i)+1) & (TX_RING_SIZE-1))
-#define RX_RING_INC(_i) (((_i)+1) & (RX_RING_SIZE-1))
-#define TX_RING_ADD(_i,_j) (((_i)+(_j)) & (TX_RING_SIZE-1))
-#define RX_RING_ADD(_i,_j) (((_i)+(_j)) & (RX_RING_SIZE-1))
-
-#define RX_BUF_SIZE ((PAGE_SIZE/2)+1) /* Fool the slab allocator :-) */
-
-static void network_rx_int(int irq, void *dev_id, struct pt_regs *ptregs);
-static void network_tx_int(int irq, void *dev_id, struct pt_regs *ptregs);
-static void network_tx_buf_gc(struct net_device *dev);
-static void network_alloc_rx_buffers(struct net_device *dev);
-static void network_free_rx_buffers(struct net_device *dev);
-static void cleanup_module(void);
-
-static struct list_head dev_list;
-
-struct net_private
-{
- struct list_head list;
- struct net_device *dev;
-
- struct net_device_stats stats;
- atomic_t tx_entries;
- unsigned int rx_resp_cons, tx_resp_cons, tx_full;
- net_ring_t *net_ring;
- net_idx_t *net_idx;
- spinlock_t tx_lock;
- unsigned int idx; /* Domain-specific index of this VIF. */
-
- /*
- * {tx,rx}_skbs store outstanding skbuffs. The first entry in each
- * array is an index into a chain of free entries.
- */
- struct sk_buff *tx_skbs[TX_RING_SIZE];
- struct sk_buff *rx_skbs[RX_RING_SIZE];
-};
-
-/* Access macros for acquiring freeing slots in {tx,rx}_skbs[]. */
-#define ADD_ID_TO_FREELIST(_list, _id) \
- (_list)[(_id)] = (_list)[0]; \
- (_list)[0] = (void *)(unsigned long)(_id);
-#define GET_ID_FROM_FREELIST(_list) \
- ({ unsigned long _id = (unsigned long)(_list)[0]; \
- (_list)[0] = (_list)[_id]; \
- _id; })
-
-
-static void dbg_network_int(int irq, void *dev_id, struct pt_regs *ptregs)
-{
- struct net_device *dev = (struct net_device *)dev_id;
- struct net_private *np = dev->priv;
- printk(KERN_ALERT "tx_full = %d, tx_entries = %d, tx_resp_cons = %d,"
- " tx_req_prod = %d, tx_resp_prod = %d, tx_event = %d, state=%d\n",
- np->tx_full, atomic_read(&np->tx_entries), np->tx_resp_cons,
- np->net_idx->tx_req_prod, np->net_idx->tx_resp_prod,
- np->net_idx->tx_event,
- test_bit(__LINK_STATE_XOFF, &dev->state));
- printk(KERN_ALERT "rx_resp_cons = %d,"
- " rx_req_prod = %d, rx_resp_prod = %d, rx_event = %d\n",
- np->rx_resp_cons, np->net_idx->rx_req_prod,
- np->net_idx->rx_resp_prod, np->net_idx->rx_event);
-}
-
-
-static int network_open(struct net_device *dev)
-{
- struct net_private *np = dev->priv;
- int i, error = 0;
-
- np->rx_resp_cons = np->tx_resp_cons = np->tx_full = 0;
- memset(&np->stats, 0, sizeof(np->stats));
- spin_lock_init(&np->tx_lock);
- atomic_set(&np->tx_entries, 0);
- memset(np->net_ring, 0, sizeof(*np->net_ring));
- memset(np->net_idx, 0, sizeof(*np->net_idx));
-
- /* Initialise {tx,rx}_skbs to be a free chain containing every entry. */
- for ( i = 0; i < TX_RING_SIZE; i++ )
- np->tx_skbs[i] = (void *)(i+1);
- for ( i = 0; i < RX_RING_SIZE; i++ )
- np->rx_skbs[i] = (void *)(i+1);
-
- network_alloc_rx_buffers(dev);
-
- error = request_irq(NET_RX_IRQ, network_rx_int,
- SA_SAMPLE_RANDOM, "net-rx", dev);
- if ( error )
- {
- printk(KERN_WARNING "%s: Could not allocate receive interrupt\n",
- dev->name);
- network_free_rx_buffers(dev);
- goto fail;
- }
-
- error = request_irq(NET_TX_IRQ, network_tx_int,
- SA_SAMPLE_RANDOM, "net-tx", dev);
- if ( error )
- {
- printk(KERN_WARNING "%s: Could not allocate transmit interrupt\n",
- dev->name);
- free_irq(NET_RX_IRQ, dev);
- network_free_rx_buffers(dev);
- goto fail;
- }
-
- error = request_irq(_EVENT_DEBUG, dbg_network_int, SA_SHIRQ,
- "debug", dev);
- if ( error )
- {
- printk(KERN_WARNING "%s: Non-fatal error -- no debug interrupt\n",
- dev->name);
- }
-
- printk("XenoLinux Virtual Network Driver installed as %s\n", dev->name);
-
- netif_start_queue(dev);
-
- MOD_INC_USE_COUNT;
-
- return 0;
-
- fail:
- kfree(np);
- return error;
-}
-
-
-static void network_tx_buf_gc(struct net_device *dev)
-{
- unsigned int i;
- struct net_private *np = dev->priv;
- struct sk_buff *skb;
- unsigned long flags;
- unsigned int prod;
- tx_entry_t *tx_ring = np->net_ring->tx_ring;
-
- spin_lock_irqsave(&np->tx_lock, flags);
-
- do {
- prod = np->net_idx->tx_resp_prod;
-
- for ( i = np->tx_resp_cons; i != prod; i = TX_RING_INC(i) )
- {
- skb = np->tx_skbs[tx_ring[i].resp.id];
- ADD_ID_TO_FREELIST(np->tx_skbs, tx_ring[i].resp.id);
- dev_kfree_skb_any(skb);
- atomic_dec(&np->tx_entries);
- }
-
- np->tx_resp_cons = prod;
-
- /* Set a new event, then check for race with update of tx_cons. */
- np->net_idx->tx_event =
- TX_RING_ADD(prod, (atomic_read(&np->tx_entries)>>1) + 1);
- smp_mb();
- }
- while ( prod != np->net_idx->tx_resp_prod );
-
- if ( np->tx_full && (atomic_read(&np->tx_entries) < TX_MAX_ENTRIES) )
- {
- np->tx_full = 0;
- netif_wake_queue(dev);
- }
-
- spin_unlock_irqrestore(&np->tx_lock, flags);
-}
-
-inline pte_t *get_ppte(void *addr)
-{
- pgd_t *pgd; pmd_t *pmd; pte_t *pte;
- pgd = pgd_offset_k( (unsigned long)addr);
- pmd = pmd_offset(pgd, (unsigned long)addr);
- pte = pte_offset(pmd, (unsigned long)addr);
- return pte;
-}
-
-static void network_alloc_rx_buffers(struct net_device *dev)
-{
- unsigned int i, id;
- struct net_private *np = dev->priv;
- struct sk_buff *skb;
- unsigned int end = RX_RING_ADD(np->rx_resp_cons, RX_MAX_ENTRIES);
-
- for ( i = np->net_idx->rx_req_prod; i != end; i = RX_RING_INC(i) )
- {
- skb = dev_alloc_skb(RX_BUF_SIZE);
- if ( skb == NULL ) break;
- skb->dev = dev;
-
- id = GET_ID_FROM_FREELIST(np->rx_skbs);
- np->rx_skbs[id] = skb;
-
- np->net_ring->rx_ring[i].req.id = (unsigned short)id;
- np->net_ring->rx_ring[i].req.addr =
- virt_to_machine(get_ppte(skb->head));
- }
-
- np->net_idx->rx_req_prod = i;
-
- np->net_idx->rx_event = RX_RING_INC(np->rx_resp_cons);
-
- /*
- * We may have allocated buffers which have entries outstanding in
- * the page update queue -- make sure we flush those first!
- */
- flush_page_update_queue();
- HYPERVISOR_net_update();
-}
-
-
-static void network_free_rx_buffers(struct net_device *dev)
-{
- unsigned int i;
- struct net_private *np = dev->priv;
- struct sk_buff *skb;
-
- for ( i = np->rx_resp_cons;
- i != np->net_idx->rx_req_prod;
- i = RX_RING_INC(i) )
- {
- skb = np->rx_skbs[np->net_ring->rx_ring[i].req.id];
- dev_kfree_skb_any(skb);
- }
-}
-
-static int network_start_xmit(struct sk_buff *skb, struct net_device *dev)
-{
- unsigned int i, id;
- struct net_private *np = (struct net_private *)dev->priv;
-
- if ( np->tx_full )
- {
- printk(KERN_ALERT "%s: full queue wasn't stopped!\n", dev->name);
- netif_stop_queue(dev);
- return -ENOBUFS;
- }
- i = np->net_idx->tx_req_prod;
-
- if ( (((unsigned long)skb->data & ~PAGE_MASK) + skb->len) >= PAGE_SIZE )
- {
- struct sk_buff *new_skb = dev_alloc_skb(RX_BUF_SIZE);
- if ( new_skb == NULL ) return 1;
- skb_put(new_skb, skb->len);
- memcpy(new_skb->data, skb->data, skb->len);
- dev_kfree_skb(skb);
- skb = new_skb;
- }
-
- id = GET_ID_FROM_FREELIST(np->tx_skbs);
- np->tx_skbs[id] = skb;
-
- np->net_ring->tx_ring[i].req.id = (unsigned short)id;
- np->net_ring->tx_ring[i].req.addr =
- phys_to_machine(virt_to_phys(skb->data));
- np->net_ring->tx_ring[i].req.size = skb->len;
- np->net_idx->tx_req_prod = TX_RING_INC(i);
- atomic_inc(&np->tx_entries);
-
- np->stats.tx_bytes += skb->len;
- np->stats.tx_packets++;
-
- spin_lock_irq(&np->tx_lock);
- if ( atomic_read(&np->tx_entries) >= TX_MAX_ENTRIES )
- {
- np->tx_full = 1;
- netif_stop_queue(dev);
- }
- spin_unlock_irq(&np->tx_lock);
-
- network_tx_buf_gc(dev);
-
- HYPERVISOR_net_update();
-
- return 0;
-}
-
-
-static void network_rx_int(int irq, void *dev_id, struct pt_regs *ptregs)
-{
- unsigned int i;
- struct net_device *dev = (struct net_device *)dev_id;
- struct net_private *np = dev->priv;
- struct sk_buff *skb;
- rx_resp_entry_t *rx;
-
- again:
- for ( i = np->rx_resp_cons;
- i != np->net_idx->rx_resp_prod;
- i = RX_RING_INC(i) )
- {
- rx = &np->net_ring->rx_ring[i].resp;
-
- skb = np->rx_skbs[rx->id];
- ADD_ID_TO_FREELIST(np->rx_skbs, rx->id);
-
- if ( rx->status != RING_STATUS_OK )
- {
- printk(KERN_ALERT "bad buffer on RX ring!(%d)\n", rx->status);
- dev_kfree_skb_any(skb);
- continue;
- }
-
- /*
- * Set up shinfo -- from alloc_skb This was particularily nasty: the
- * shared info is hidden at the back of the data area (presumably so it
- * can be shared), but on page flip it gets very spunked.
- */
- atomic_set(&(skb_shinfo(skb)->dataref), 1);
- skb_shinfo(skb)->nr_frags = 0;
- skb_shinfo(skb)->frag_list = NULL;
-
- phys_to_machine_mapping[virt_to_phys(skb->head) >> PAGE_SHIFT] =
- (*(unsigned long *)get_ppte(skb->head)) >> PAGE_SHIFT;
-
- if ( rx->offset < 16 )
- {
- printk(KERN_ALERT "need pkt offset >= 16 (got %d)\n", rx->offset);
- dev_kfree_skb_any(skb);
- continue;
- }
-
- skb_reserve(skb, rx->offset - 16);
-
- skb_put(skb, rx->size);
- skb->protocol = eth_type_trans(skb, dev);
-
- np->stats.rx_packets++;
-
- np->stats.rx_bytes += rx->size;
- netif_rx(skb);
- dev->last_rx = jiffies;
- }
-
- np->rx_resp_cons = i;
-
- network_alloc_rx_buffers(dev);
-
- /* Deal with hypervisor racing our resetting of rx_event. */
- smp_mb();
- if ( np->net_idx->rx_resp_prod != i ) goto again;
-}
-
-
-static void network_tx_int(int irq, void *dev_id, struct pt_regs *ptregs)
-{
- struct net_device *dev = (struct net_device *)dev_id;
- network_tx_buf_gc(dev);
-}
-
-
-int network_close(struct net_device *dev)
-{
- netif_stop_queue(dev);
-
- free_irq(NET_RX_IRQ, dev);
- free_irq(NET_TX_IRQ, dev);
-
- /*
- * XXXX This cannot be done safely until be have a proper interface
- * for setting up and tearing down virtual interfaces on the fly.
- * Currently the receive buffers are locked down by Xen and we have
- * no sensible way of retrieving them.
- */
-#if 0
- network_free_rx_buffers(dev);
- kfree(np->net_ring->rx_ring);
- kfree(np->net_ring->tx_ring);
-#endif
-
- MOD_DEC_USE_COUNT;
-
- return 0;
-}
-
-
-static struct net_device_stats *network_get_stats(struct net_device *dev)
-{
- struct net_private *np = (struct net_private *)dev->priv;
- return &np->stats;
-}
-
-
-/*
- * This notifier is installed for domain 0 only.
- * All other domains have VFR rules installed on their behalf by domain 0
- * when they are created. For bootstrap, Xen creates wildcard rules for
- * domain 0 -- this notifier is used to detect when we find our proper
- * IP address, so we can poke down proper rules and remove the wildcards.
- */
-static int inetdev_notify(struct notifier_block *this,
- unsigned long event,
- void *ptr)
-{
- struct in_ifaddr *ifa = (struct in_ifaddr *)ptr;
- struct net_device *dev = ifa->ifa_dev->dev;
- struct list_head *ent;
- struct net_private *np;
- int idx = -1;
- network_op_t op;
- static int removed_bootstrap_rules = 0;
-
- list_for_each ( ent, &dev_list )
- {
- np = list_entry(dev_list.next, struct net_private, list);
- if ( np->dev == dev )
- idx = np->idx;
- }
-
- if ( idx == -1 )
- goto out;
-
- memset(&op, 0, sizeof(op));
- op.u.net_rule.proto = NETWORK_PROTO_ANY;
- op.u.net_rule.action = NETWORK_ACTION_ACCEPT;
-
- if ( event == NETDEV_UP )
- op.cmd = NETWORK_OP_ADDRULE;
- else if ( event == NETDEV_DOWN )
- op.cmd = NETWORK_OP_DELETERULE;
- else
- goto out;
-
- op.u.net_rule.src_vif = idx;
- op.u.net_rule.dst_vif = VIF_PHYSICAL_INTERFACE;
- op.u.net_rule.src_addr = ntohl(ifa->ifa_address);
- op.u.net_rule.src_addr_mask = ~0UL;
- op.u.net_rule.dst_addr = 0;
- op.u.net_rule.dst_addr_mask = 0;
- (void)HYPERVISOR_network_op(&op);
-
- op.u.net_rule.src_vif = VIF_ANY_INTERFACE;
- op.u.net_rule.dst_vif = idx;
- op.u.net_rule.src_addr = 0;
- op.u.net_rule.src_addr_mask = 0;
- op.u.net_rule.dst_addr = ntohl(ifa->ifa_address);
- op.u.net_rule.dst_addr_mask = ~0UL;
- (void)HYPERVISOR_network_op(&op);
-
- /*
- * When the first real interface is brought up we delete the start-of-day
- * bootstrap rules -- they were only installed to allow an initial DHCP
- * request and response.
- */
- if ( (idx == 0) && (event == NETDEV_UP) && !removed_bootstrap_rules )
- {
- memset(&op, 0, sizeof(op));
- op.cmd = NETWORK_OP_DELETERULE;
- op.u.net_rule.proto = NETWORK_PROTO_ANY;
- op.u.net_rule.action = NETWORK_ACTION_ACCEPT;
- op.u.net_rule.src_vif = 0;
- op.u.net_rule.dst_vif = VIF_PHYSICAL_INTERFACE;
- (void)HYPERVISOR_network_op(&op);
- op.u.net_rule.src_vif = VIF_ANY_INTERFACE;
- op.u.net_rule.dst_vif = 0;
- (void)HYPERVISOR_network_op(&op);
-
- removed_bootstrap_rules = 1;
- }
-
- out:
- return NOTIFY_DONE;
-}
-
-static struct notifier_block notifier_inetdev = {
- .notifier_call = inetdev_notify,
- .next = NULL,
- .priority = 0
-};
-
-
-int __init init_module(void)
-{
- int i, fixmap_idx=-1, err;
- struct net_device *dev;
- struct net_private *np;
-
- INIT_LIST_HEAD(&dev_list);
-
- if ( start_info.dom_id == 0 )
- {
- /*
- * Domain 0 creates wildcard rules to allow DHCP to find its first IP
- * address. These wildcard rules are deleted when the first inet
- * interface is brought up.
- */
- network_op_t op;
- memset(&op, 0, sizeof(op));
- op.cmd = NETWORK_OP_ADDRULE;
- op.u.net_rule.proto = NETWORK_PROTO_ANY;
- op.u.net_rule.action = NETWORK_ACTION_ACCEPT;
- op.u.net_rule.src_vif = 0;
- op.u.net_rule.dst_vif = VIF_PHYSICAL_INTERFACE;
- (void)HYPERVISOR_network_op(&op);
- op.u.net_rule.src_vif = VIF_ANY_INTERFACE;
- op.u.net_rule.dst_vif = 0;
- (void)HYPERVISOR_network_op(&op);
-
- /*
- * Domain 0 must poke its own network rules as it discovers its IP
- * addresses. All other domains have a privileged "parent" to do this
- * for them at start of day.
- */
- (void)register_inetaddr_notifier(¬ifier_inetdev);
- }
-
- for ( i = 0; i < MAX_DOMAIN_VIFS; i++ )
- {
- if ( start_info.net_rings[i] == 0 )
- continue;
-
- /* We actually only support up to 4 vifs right now. */
- if ( ++fixmap_idx == 4 )
- break;
-
- dev = alloc_etherdev(sizeof(struct net_private));
- if ( dev == NULL )
- {
- err = -ENOMEM;
- goto fail;
- }
-
- set_fixmap(FIX_NETRING0_BASE+fixmap_idx, start_info.net_rings[i]);
-
- np = dev->priv;
- np->net_ring = (net_ring_t *)fix_to_virt(FIX_NETRING0_BASE+fixmap_idx);
- np->net_idx = &HYPERVISOR_shared_info->net_idx[i];
- np->idx = i;
-
- SET_MODULE_OWNER(dev);
- dev->open = network_open;
- dev->hard_start_xmit = network_start_xmit;
- dev->stop = network_close;
- dev->get_stats = network_get_stats;
-
- memcpy(dev->dev_addr, start_info.net_vmac[i], ETH_ALEN);
-
- if ( (err = register_netdev(dev)) != 0 )
- {
- kfree(dev);
- goto fail;
- }
-
- np->dev = dev;
- list_add(&np->list, &dev_list);
- }
-
- return 0;
-
- fail:
- cleanup_module();
- return err;
-}
-
-
-static void cleanup_module(void)
-{
- struct net_private *np;
- struct net_device *dev;
-
- while ( !list_empty(&dev_list) )
- {
- np = list_entry(dev_list.next, struct net_private, list);
- list_del(&np->list);
- dev = np->dev;
- unregister_netdev(dev);
- kfree(dev);
- }
-
- if ( start_info.dom_id == 0 )
- (void)unregister_inetaddr_notifier(¬ifier_inetdev);
-}
-
-
-module_init(init_module);
-module_exit(cleanup_module);
+++ /dev/null
-
-.S.o:
- $(CC) $(AFLAGS) -traditional -c $< -o $*.o
-
-all: kernel.o head.o init_task.o
-
-O_TARGET := kernel.o
-
-export-objs := i386_ksyms.o
-
-obj-y := process.o semaphore.o signal.o entry.o traps.o irq.o \
- ptrace.o ioport.o ldt.o setup.o time.o sys_i386.o \
- i386_ksyms.o i387.o hypervisor.o
-
-include $(TOPDIR)/Rules.make
+++ /dev/null
-/*
- * linux/arch/i386/entry.S
- *
- * Copyright (C) 1991, 1992 Linus Torvalds
- */
-
-/*
- * entry.S contains the system-call and fault low-level handling routines.
- * This also contains the timer-interrupt handler, as well as all interrupts
- * and faults that can result in a task-switch.
- *
- * NOTE: This code handles signal-recognition, which happens every time
- * after a timer-interrupt and after each system call.
- *
- * I changed all the .align's to 4 (16 byte alignment), as that's faster
- * on a 486.
- *
- * Stack layout in 'ret_from_system_call':
- * ptrace needs to have all regs on the stack.
- * if the order here is changed, it needs to be
- * updated in fork.c:copy_process, signal.c:do_signal,
- * ptrace.c and ptrace.h
- *
- * 0(%esp) - %ebx
- * 4(%esp) - %ecx
- * 8(%esp) - %edx
- * C(%esp) - %esi
- * 10(%esp) - %edi
- * 14(%esp) - %ebp
- * 18(%esp) - %eax
- * 1C(%esp) - %ds
- * 20(%esp) - %es
- * 24(%esp) - orig_eax
- * 28(%esp) - %eip
- * 2C(%esp) - %cs
- * 30(%esp) - %eflags
- * 34(%esp) - %oldesp
- * 38(%esp) - %oldss
- *
- * "current" is in register %ebx during any slow entries.
- */
-
-#include <linux/config.h>
-#include <linux/sys.h>
-#include <linux/linkage.h>
-#include <asm/segment.h>
-#include <asm/smp.h>
-
-EBX = 0x00
-ECX = 0x04
-EDX = 0x08
-ESI = 0x0C
-EDI = 0x10
-EBP = 0x14
-EAX = 0x18
-DS = 0x1C
-ES = 0x20
-ORIG_EAX = 0x24
-EIP = 0x28
-CS = 0x2C
-EFLAGS = 0x30
-OLDESP = 0x34
-OLDSS = 0x38
-
-CF_MASK = 0x00000001
-TF_MASK = 0x00000100
-IF_MASK = 0x00000200
-DF_MASK = 0x00000400
-NT_MASK = 0x00004000
-
-/*
- * these are offsets into the task-struct.
- */
-state = 0
-flags = 4
-sigpending = 8
-addr_limit = 12
-exec_domain = 16
-need_resched = 20
-tsk_ptrace = 24
-processor = 52
-
-ENOSYS = 38
-
-
-#define SAVE_ALL \
- cld; \
- pushl %es; \
- pushl %ds; \
- pushl %eax; \
- pushl %ebp; \
- pushl %edi; \
- pushl %esi; \
- pushl %edx; \
- pushl %ecx; \
- pushl %ebx; \
- movl $(__KERNEL_DS),%edx; \
- movl %edx,%ds; \
- movl %edx,%es;
-
-#define RESTORE_ALL \
- popl %ebx; \
- popl %ecx; \
- popl %edx; \
- popl %esi; \
- popl %edi; \
- popl %ebp; \
- popl %eax; \
-1: popl %ds; \
-2: popl %es; \
- addl $4,%esp; \
-3: iret; \
-.section .fixup,"ax"; \
-4: movl $0,(%esp); \
- jmp 1b; \
-5: movl $0,(%esp); \
- jmp 2b; \
-6: pushl %ss; \
- popl %ds; \
- pushl %ss; \
- popl %es; \
- pushl $11; \
- call do_exit; \
-.previous; \
-.section __ex_table,"a";\
- .align 4; \
- .long 1b,4b; \
- .long 2b,5b; \
- .long 3b,6b; \
-.previous
-
-#define GET_CURRENT(reg) \
- movl $-8192, reg; \
- andl %esp, reg
-
-ENTRY(lcall7)
- pushfl # We get a different stack layout with call
- pushl %eax # gates, which has to be cleaned up later..
- SAVE_ALL
- movl EIP(%esp),%eax # due to call gates, this is eflags, not eip..
- movl CS(%esp),%edx # this is eip..
- movl EFLAGS(%esp),%ecx # and this is cs..
- movl %eax,EFLAGS(%esp) #
- andl $~(NT_MASK|TF_MASK|DF_MASK), %eax
- pushl %eax
- popfl
- movl %edx,EIP(%esp) # Now we move them to their "normal" places
- movl %ecx,CS(%esp) #
- movl %esp,%ebx
- pushl %ebx
- andl $-8192,%ebx # GET_CURRENT
- movl exec_domain(%ebx),%edx # Get the execution domain
- movl 4(%edx),%edx # Get the lcall7 handler for the domain
- pushl $0x7
- call *%edx
- addl $4, %esp
- popl %eax
- jmp ret_from_sys_call
-
-ENTRY(lcall27)
- pushfl # We get a different stack layout with call
- pushl %eax # gates, which has to be cleaned up later..
- SAVE_ALL
- movl EIP(%esp),%eax # due to call gates, this is eflags, not eip..
- movl CS(%esp),%edx # this is eip..
- movl EFLAGS(%esp),%ecx # and this is cs..
- movl %eax,EFLAGS(%esp) #
- andl $~(NT_MASK|TF_MASK|DF_MASK), %eax
- pushl %eax
- popfl
- movl %edx,EIP(%esp) # Now we move them to their "normal" places
- movl %ecx,CS(%esp) #
- movl %esp,%ebx
- pushl %ebx
- andl $-8192,%ebx # GET_CURRENT
- movl exec_domain(%ebx),%edx # Get the execution domain
- movl 4(%edx),%edx # Get the lcall7 handler for the domain
- pushl $0x27
- call *%edx
- addl $4, %esp
- popl %eax
- jmp ret_from_sys_call
-
-
-ENTRY(ret_from_fork)
- pushl %ebx
- call SYMBOL_NAME(schedule_tail)
- addl $4, %esp
- GET_CURRENT(%ebx)
- testb $0x02,tsk_ptrace(%ebx) # PT_TRACESYS
- jne tracesys_exit
- jmp ret_from_sys_call
-
-/*
- * Return to user mode is not as complex as all this looks,
- * but we want the default path for a system call return to
- * go as quickly as possible which is why some of this is
- * less clear than it otherwise should be.
- */
-
-ENTRY(system_call)
- pushl %eax # save orig_eax
- SAVE_ALL
- GET_CURRENT(%ebx)
- testb $0x02,tsk_ptrace(%ebx) # PT_TRACESYS
- jne tracesys
- cmpl $(NR_syscalls),%eax
- jae badsys
- call *SYMBOL_NAME(sys_call_table)(,%eax,4)
- movl %eax,EAX(%esp) # save the return value
-ENTRY(ret_from_sys_call)
- movl SYMBOL_NAME(HYPERVISOR_shared_info),%esi
- btrl $EVENTS_MASTER_ENABLE_BIT,4(%esi) # make tests atomic
-ret_syscall_tests:
- cmpl $0,need_resched(%ebx)
- jne reschedule
- cmpl $0,sigpending(%ebx)
- je safesti # ensure need_resched updates are seen
-signal_return:
- btsl $EVENTS_MASTER_ENABLE_BIT,4(%esi) # reenable event callbacks
- movl %esp,%eax
- xorl %edx,%edx
- call SYMBOL_NAME(do_signal)
- jmp ret_from_sys_call
-
- ALIGN
-restore_all:
- RESTORE_ALL
-
- ALIGN
-tracesys:
- movl $-ENOSYS,EAX(%esp)
- call SYMBOL_NAME(syscall_trace)
- movl ORIG_EAX(%esp),%eax
- cmpl $(NR_syscalls),%eax
- jae tracesys_exit
- call *SYMBOL_NAME(sys_call_table)(,%eax,4)
- movl %eax,EAX(%esp) # save the return value
-tracesys_exit:
- call SYMBOL_NAME(syscall_trace)
- jmp ret_from_sys_call
-badsys:
- movl $-ENOSYS,EAX(%esp)
- jmp ret_from_sys_call
-
- ALIGN
-ENTRY(ret_from_intr)
- GET_CURRENT(%ebx)
-ret_from_exception:
- movb CS(%esp),%al
- testl $2,%eax
- jne ret_from_sys_call
- jmp restore_all
-
- ALIGN
-reschedule:
- btsl $EVENTS_MASTER_ENABLE_BIT,4(%esi) # reenable event callbacks
- call SYMBOL_NAME(schedule) # test
- jmp ret_from_sys_call
-
-ENTRY(divide_error)
- pushl $0 # no error code
- pushl $ SYMBOL_NAME(do_divide_error)
- ALIGN
-error_code:
- pushl %ds
- pushl %eax
- xorl %eax,%eax
- pushl %ebp
- pushl %edi
- pushl %esi
- pushl %edx
- decl %eax # eax = -1
- pushl %ecx
- pushl %ebx
- GET_CURRENT(%ebx)
- cld
- movl %es,%ecx
- movl ORIG_EAX(%esp), %esi # get the error code
- movl ES(%esp), %edi # get the function address
- movl %eax, ORIG_EAX(%esp)
- movl %ecx, ES(%esp)
- movl %esp,%edx
- pushl %esi # push the error code
- pushl %edx # push the pt_regs pointer
- movl $(__KERNEL_DS),%edx
- movl %edx,%ds
- movl %edx,%es
- call *%edi
- addl $8,%esp
- jmp ret_from_exception
-
-# A note on the "critical region" in our callback handler.
-# We want to avoid stacking callback handlers due to events occurring
-# during handling of the last event. To do this, we keep events disabled
-# until we've done all processing. HOWEVER, we must enable events before
-# popping the stack frame (can't be done atomically) and so it would still
-# be possible to get enough handler activations to overflow the stack.
-# Although unlikely, bugs of that kind are hard to track down, so we'd
-# like to avoid the possibility.
-# So, on entry to the handler we detect whether we interrupted an
-# existing activation in its critical region -- if so, we pop the current
-# activation and restart the handler using the previous one.
-ENTRY(hypervisor_callback)
- pushl %eax
- SAVE_ALL
- GET_CURRENT(%ebx)
- movl EIP(%esp),%eax
- cmpl $scrit,%eax
- jb 11f
- cmpl $ecrit,%eax
- jb critical_region_fixup
-11: push %esp
- call do_hypervisor_callback
- add $4,%esp
- movl SYMBOL_NAME(HYPERVISOR_shared_info),%esi
- xorl %eax,%eax
- movb CS(%esp),%cl
- test $2,%cl # slow return to ring 2 or 3
- jne ret_syscall_tests
-safesti:btsl $EVENTS_MASTER_ENABLE_BIT,4(%esi) # reenable event callbacks
-scrit: /**** START OF CRITICAL REGION ****/
- cmpl %eax,(%esi)
- jne 14f # process more events if necessary...
- RESTORE_ALL
-14: btrl $EVENTS_MASTER_ENABLE_BIT,4(%esi)
- jmp 11b
-ecrit: /**** END OF CRITICAL REGION ****/
-# [How we do the fixup]. We want to merge the current stack frame with the
-# just-interrupted frame. How we do this depends on where in the critical
-# region the interrupted handler was executing, and so how many saved
-# registers are in each frame. We do this quickly using the lookup table
-# 'critical_fixup_table'. For each byte offset in the critical region, it
-# provides the number of bytes which have already been popped from the
-# interrupted stack frame.
-critical_region_fixup:
- addl $critical_fixup_table-scrit,%eax
- movzbl (%eax),%eax # %eax contains num bytes popped
- mov %esp,%esi
- add %eax,%esi # %esi points at end of src region
- mov %esp,%edi
- add $0x34,%edi # %edi points at end of dst region
- mov %eax,%ecx
- shr $2,%ecx # convert words to bytes
- je 16f # skip loop if nothing to copy
-15: subl $4,%esi # pre-decrementing copy loop
- subl $4,%edi
- movl (%esi),%eax
- movl %eax,(%edi)
- loop 15b
-16: movl %edi,%esp # final %edi is top of merged stack
- jmp 11b
-
-critical_fixup_table:
- .byte 0x00,0x00 # cmpl %eax,(%esi)
- .byte 0x00,0x00 # jne 14f
- .byte 0x00 # pop %ebx
- .byte 0x04 # pop %ecx
- .byte 0x08 # pop %edx
- .byte 0x0c # pop %esi
- .byte 0x10 # pop %edi
- .byte 0x14 # pop %ebp
- .byte 0x18 # pop %eax
- .byte 0x1c # pop %ds
- .byte 0x20 # pop %es
- .byte 0x24,0x24,0x24 # add $4,%esp
- .byte 0x28 # iret
- .byte 0x00,0x00,0x00,0x00,0x00 # btrl $31,4(%esi)
- .byte 0x00,0x00 # jmp 11b
-
-# Hypervisor uses this for application faults while it executes.
-ENTRY(failsafe_callback)
-1: pop %ds
-2: pop %es
-3: pop %fs
-4: pop %gs
-5: iret
-.section .fixup,"ax"; \
-6: movl $0,(%esp); \
- jmp 1b; \
-7: movl $0,(%esp); \
- jmp 2b; \
-8: movl $0,(%esp); \
- jmp 3b; \
-9: movl $0,(%esp); \
- jmp 4b; \
-10: pushl %ss; \
- popl %ds; \
- pushl %ss; \
- popl %es; \
- pushl $11; \
- call do_exit; \
-.previous; \
-.section __ex_table,"a";\
- .align 4; \
- .long 1b,6b; \
- .long 2b,7b; \
- .long 3b,8b; \
- .long 4b,9b; \
- .long 5b,10b; \
-.previous
-
-ENTRY(coprocessor_error)
- pushl $0
- pushl $ SYMBOL_NAME(do_coprocessor_error)
- jmp error_code
-
-ENTRY(simd_coprocessor_error)
- pushl $0
- pushl $ SYMBOL_NAME(do_simd_coprocessor_error)
- jmp error_code
-
-ENTRY(device_not_available)
- pushl $-1 # mark this as an int
- SAVE_ALL
- GET_CURRENT(%ebx)
- call SYMBOL_NAME(math_state_restore)
- jmp ret_from_exception
-
-ENTRY(debug)
- pushl $0
- pushl $ SYMBOL_NAME(do_debug)
- jmp error_code
-
-ENTRY(int3)
- pushl $0
- pushl $ SYMBOL_NAME(do_int3)
- jmp error_code
-
-ENTRY(overflow)
- pushl $0
- pushl $ SYMBOL_NAME(do_overflow)
- jmp error_code
-
-ENTRY(bounds)
- pushl $0
- pushl $ SYMBOL_NAME(do_bounds)
- jmp error_code
-
-ENTRY(invalid_op)
- pushl $0
- pushl $ SYMBOL_NAME(do_invalid_op)
- jmp error_code
-
-ENTRY(coprocessor_segment_overrun)
- pushl $0
- pushl $ SYMBOL_NAME(do_coprocessor_segment_overrun)
- jmp error_code
-
-ENTRY(double_fault)
- pushl $ SYMBOL_NAME(do_double_fault)
- jmp error_code
-
-ENTRY(invalid_TSS)
- pushl $ SYMBOL_NAME(do_invalid_TSS)
- jmp error_code
-
-ENTRY(segment_not_present)
- pushl $ SYMBOL_NAME(do_segment_not_present)
- jmp error_code
-
-ENTRY(stack_segment)
- pushl $ SYMBOL_NAME(do_stack_segment)
- jmp error_code
-
-ENTRY(general_protection)
- pushl $ SYMBOL_NAME(do_general_protection)
- jmp error_code
-
-ENTRY(alignment_check)
- pushl $ SYMBOL_NAME(do_alignment_check)
- jmp error_code
-
-# This handler is special, because it gets an extra value on its stack,
-# which is the linear faulting address.
-ENTRY(page_fault)
- pushl %ds
- pushl %eax
- xorl %eax,%eax
- pushl %ebp
- pushl %edi
- pushl %esi
- pushl %edx
- decl %eax # eax = -1
- pushl %ecx
- pushl %ebx
- GET_CURRENT(%ebx)
- cld
- movl %es,%ecx
- movl ORIG_EAX(%esp), %esi # get the error code
- movl ES(%esp), %edi # get the faulting address
- movl %eax, ORIG_EAX(%esp)
- movl %ecx, ES(%esp)
- movl %esp,%edx
- pushl %edi # push the faulting address
- pushl %esi # push the error code
- pushl %edx # push the pt_regs pointer
- movl $(__KERNEL_DS),%edx
- movl %edx,%ds
- movl %edx,%es
- call SYMBOL_NAME(do_page_fault)
- addl $12,%esp
- jmp ret_from_exception
-
-ENTRY(machine_check)
- pushl $0
- pushl $ SYMBOL_NAME(do_machine_check)
- jmp error_code
-
-ENTRY(spurious_interrupt_bug)
- pushl $0
- pushl $ SYMBOL_NAME(do_spurious_interrupt_bug)
- jmp error_code
-
-.data
-ENTRY(sys_call_table)
- .long SYMBOL_NAME(sys_ni_syscall) /* 0 - old "setup()" system call*/
- .long SYMBOL_NAME(sys_exit)
- .long SYMBOL_NAME(sys_fork)
- .long SYMBOL_NAME(sys_read)
- .long SYMBOL_NAME(sys_write)
- .long SYMBOL_NAME(sys_open) /* 5 */
- .long SYMBOL_NAME(sys_close)
- .long SYMBOL_NAME(sys_waitpid)
- .long SYMBOL_NAME(sys_creat)
- .long SYMBOL_NAME(sys_link)
- .long SYMBOL_NAME(sys_unlink) /* 10 */
- .long SYMBOL_NAME(sys_execve)
- .long SYMBOL_NAME(sys_chdir)
- .long SYMBOL_NAME(sys_time)
- .long SYMBOL_NAME(sys_mknod)
- .long SYMBOL_NAME(sys_chmod) /* 15 */
- .long SYMBOL_NAME(sys_lchown16)
- .long SYMBOL_NAME(sys_ni_syscall) /* old break syscall holder */
- .long SYMBOL_NAME(sys_stat)
- .long SYMBOL_NAME(sys_lseek)
- .long SYMBOL_NAME(sys_getpid) /* 20 */
- .long SYMBOL_NAME(sys_mount)
- .long SYMBOL_NAME(sys_oldumount)
- .long SYMBOL_NAME(sys_setuid16)
- .long SYMBOL_NAME(sys_getuid16)
- .long SYMBOL_NAME(sys_stime) /* 25 */
- .long SYMBOL_NAME(sys_ptrace)
- .long SYMBOL_NAME(sys_alarm)
- .long SYMBOL_NAME(sys_fstat)
- .long SYMBOL_NAME(sys_pause)
- .long SYMBOL_NAME(sys_utime) /* 30 */
- .long SYMBOL_NAME(sys_ni_syscall) /* old stty syscall holder */
- .long SYMBOL_NAME(sys_ni_syscall) /* old gtty syscall holder */
- .long SYMBOL_NAME(sys_access)
- .long SYMBOL_NAME(sys_nice)
- .long SYMBOL_NAME(sys_ni_syscall) /* 35 */ /* old ftime syscall holder */
- .long SYMBOL_NAME(sys_sync)
- .long SYMBOL_NAME(sys_kill)
- .long SYMBOL_NAME(sys_rename)
- .long SYMBOL_NAME(sys_mkdir)
- .long SYMBOL_NAME(sys_rmdir) /* 40 */
- .long SYMBOL_NAME(sys_dup)
- .long SYMBOL_NAME(sys_pipe)
- .long SYMBOL_NAME(sys_times)
- .long SYMBOL_NAME(sys_ni_syscall) /* old prof syscall holder */
- .long SYMBOL_NAME(sys_brk) /* 45 */
- .long SYMBOL_NAME(sys_setgid16)
- .long SYMBOL_NAME(sys_getgid16)
- .long SYMBOL_NAME(sys_signal)
- .long SYMBOL_NAME(sys_geteuid16)
- .long SYMBOL_NAME(sys_getegid16) /* 50 */
- .long SYMBOL_NAME(sys_acct)
- .long SYMBOL_NAME(sys_umount) /* recycled never used phys() */
- .long SYMBOL_NAME(sys_ni_syscall) /* old lock syscall holder */
- .long SYMBOL_NAME(sys_ioctl)
- .long SYMBOL_NAME(sys_fcntl) /* 55 */
- .long SYMBOL_NAME(sys_ni_syscall) /* old mpx syscall holder */
- .long SYMBOL_NAME(sys_setpgid)
- .long SYMBOL_NAME(sys_ni_syscall) /* old ulimit syscall holder */
- .long SYMBOL_NAME(sys_olduname)
- .long SYMBOL_NAME(sys_umask) /* 60 */
- .long SYMBOL_NAME(sys_chroot)
- .long SYMBOL_NAME(sys_ustat)
- .long SYMBOL_NAME(sys_dup2)
- .long SYMBOL_NAME(sys_getppid)
- .long SYMBOL_NAME(sys_getpgrp) /* 65 */
- .long SYMBOL_NAME(sys_setsid)
- .long SYMBOL_NAME(sys_sigaction)
- .long SYMBOL_NAME(sys_sgetmask)
- .long SYMBOL_NAME(sys_ssetmask)
- .long SYMBOL_NAME(sys_setreuid16) /* 70 */
- .long SYMBOL_NAME(sys_setregid16)
- .long SYMBOL_NAME(sys_sigsuspend)
- .long SYMBOL_NAME(sys_sigpending)
- .long SYMBOL_NAME(sys_sethostname)
- .long SYMBOL_NAME(sys_setrlimit) /* 75 */
- .long SYMBOL_NAME(sys_old_getrlimit)
- .long SYMBOL_NAME(sys_getrusage)
- .long SYMBOL_NAME(sys_gettimeofday)
- .long SYMBOL_NAME(sys_settimeofday)
- .long SYMBOL_NAME(sys_getgroups16) /* 80 */
- .long SYMBOL_NAME(sys_setgroups16)
- .long SYMBOL_NAME(old_select)
- .long SYMBOL_NAME(sys_symlink)
- .long SYMBOL_NAME(sys_lstat)
- .long SYMBOL_NAME(sys_readlink) /* 85 */
- .long SYMBOL_NAME(sys_uselib)
- .long SYMBOL_NAME(sys_swapon)
- .long SYMBOL_NAME(sys_reboot)
- .long SYMBOL_NAME(old_readdir)
- .long SYMBOL_NAME(old_mmap) /* 90 */
- .long SYMBOL_NAME(sys_munmap)
- .long SYMBOL_NAME(sys_truncate)
- .long SYMBOL_NAME(sys_ftruncate)
- .long SYMBOL_NAME(sys_fchmod)
- .long SYMBOL_NAME(sys_fchown16) /* 95 */
- .long SYMBOL_NAME(sys_getpriority)
- .long SYMBOL_NAME(sys_setpriority)
- .long SYMBOL_NAME(sys_ni_syscall) /* old profil syscall holder */
- .long SYMBOL_NAME(sys_statfs)
- .long SYMBOL_NAME(sys_fstatfs) /* 100 */
- .long SYMBOL_NAME(sys_ioperm)
- .long SYMBOL_NAME(sys_socketcall)
- .long SYMBOL_NAME(sys_syslog)
- .long SYMBOL_NAME(sys_setitimer)
- .long SYMBOL_NAME(sys_getitimer) /* 105 */
- .long SYMBOL_NAME(sys_newstat)
- .long SYMBOL_NAME(sys_newlstat)
- .long SYMBOL_NAME(sys_newfstat)
- .long SYMBOL_NAME(sys_uname)
- .long SYMBOL_NAME(sys_iopl) /* 110 */
- .long SYMBOL_NAME(sys_vhangup)
- .long SYMBOL_NAME(sys_ni_syscall) /* old "idle" system call */
- .long SYMBOL_NAME(sys_ni_syscall) /* was VM86 */
- .long SYMBOL_NAME(sys_wait4)
- .long SYMBOL_NAME(sys_swapoff) /* 115 */
- .long SYMBOL_NAME(sys_sysinfo)
- .long SYMBOL_NAME(sys_ipc)
- .long SYMBOL_NAME(sys_fsync)
- .long SYMBOL_NAME(sys_sigreturn)
- .long SYMBOL_NAME(sys_clone) /* 120 */
- .long SYMBOL_NAME(sys_setdomainname)
- .long SYMBOL_NAME(sys_newuname)
- .long SYMBOL_NAME(sys_modify_ldt)
- .long SYMBOL_NAME(sys_adjtimex)
- .long SYMBOL_NAME(sys_mprotect) /* 125 */
- .long SYMBOL_NAME(sys_sigprocmask)
- .long SYMBOL_NAME(sys_create_module)
- .long SYMBOL_NAME(sys_init_module)
- .long SYMBOL_NAME(sys_delete_module)
- .long SYMBOL_NAME(sys_get_kernel_syms) /* 130 */
- .long SYMBOL_NAME(sys_quotactl)
- .long SYMBOL_NAME(sys_getpgid)
- .long SYMBOL_NAME(sys_fchdir)
- .long SYMBOL_NAME(sys_bdflush)
- .long SYMBOL_NAME(sys_sysfs) /* 135 */
- .long SYMBOL_NAME(sys_personality)
- .long SYMBOL_NAME(sys_ni_syscall) /* for afs_syscall */
- .long SYMBOL_NAME(sys_setfsuid16)
- .long SYMBOL_NAME(sys_setfsgid16)
- .long SYMBOL_NAME(sys_llseek) /* 140 */
- .long SYMBOL_NAME(sys_getdents)
- .long SYMBOL_NAME(sys_select)
- .long SYMBOL_NAME(sys_flock)
- .long SYMBOL_NAME(sys_msync)
- .long SYMBOL_NAME(sys_readv) /* 145 */
- .long SYMBOL_NAME(sys_writev)
- .long SYMBOL_NAME(sys_getsid)
- .long SYMBOL_NAME(sys_fdatasync)
- .long SYMBOL_NAME(sys_sysctl)
- .long SYMBOL_NAME(sys_mlock) /* 150 */
- .long SYMBOL_NAME(sys_munlock)
- .long SYMBOL_NAME(sys_mlockall)
- .long SYMBOL_NAME(sys_munlockall)
- .long SYMBOL_NAME(sys_sched_setparam)
- .long SYMBOL_NAME(sys_sched_getparam) /* 155 */
- .long SYMBOL_NAME(sys_sched_setscheduler)
- .long SYMBOL_NAME(sys_sched_getscheduler)
- .long SYMBOL_NAME(sys_sched_yield)
- .long SYMBOL_NAME(sys_sched_get_priority_max)
- .long SYMBOL_NAME(sys_sched_get_priority_min) /* 160 */
- .long SYMBOL_NAME(sys_sched_rr_get_interval)
- .long SYMBOL_NAME(sys_nanosleep)
- .long SYMBOL_NAME(sys_mremap)
- .long SYMBOL_NAME(sys_setresuid16)
- .long SYMBOL_NAME(sys_getresuid16) /* 165 */
- .long SYMBOL_NAME(sys_ni_syscall) /* was VM86 */
- .long SYMBOL_NAME(sys_query_module)
- .long SYMBOL_NAME(sys_poll)
- .long SYMBOL_NAME(sys_nfsservctl)
- .long SYMBOL_NAME(sys_setresgid16) /* 170 */
- .long SYMBOL_NAME(sys_getresgid16)
- .long SYMBOL_NAME(sys_prctl)
- .long SYMBOL_NAME(sys_rt_sigreturn)
- .long SYMBOL_NAME(sys_rt_sigaction)
- .long SYMBOL_NAME(sys_rt_sigprocmask) /* 175 */
- .long SYMBOL_NAME(sys_rt_sigpending)
- .long SYMBOL_NAME(sys_rt_sigtimedwait)
- .long SYMBOL_NAME(sys_rt_sigqueueinfo)
- .long SYMBOL_NAME(sys_rt_sigsuspend)
- .long SYMBOL_NAME(sys_pread) /* 180 */
- .long SYMBOL_NAME(sys_pwrite)
- .long SYMBOL_NAME(sys_chown16)
- .long SYMBOL_NAME(sys_getcwd)
- .long SYMBOL_NAME(sys_capget)
- .long SYMBOL_NAME(sys_capset) /* 185 */
- .long SYMBOL_NAME(sys_sigaltstack)
- .long SYMBOL_NAME(sys_sendfile)
- .long SYMBOL_NAME(sys_ni_syscall) /* streams1 */
- .long SYMBOL_NAME(sys_ni_syscall) /* streams2 */
- .long SYMBOL_NAME(sys_vfork) /* 190 */
- .long SYMBOL_NAME(sys_getrlimit)
- .long SYMBOL_NAME(sys_mmap2)
- .long SYMBOL_NAME(sys_truncate64)
- .long SYMBOL_NAME(sys_ftruncate64)
- .long SYMBOL_NAME(sys_stat64) /* 195 */
- .long SYMBOL_NAME(sys_lstat64)
- .long SYMBOL_NAME(sys_fstat64)
- .long SYMBOL_NAME(sys_lchown)
- .long SYMBOL_NAME(sys_getuid)
- .long SYMBOL_NAME(sys_getgid) /* 200 */
- .long SYMBOL_NAME(sys_geteuid)
- .long SYMBOL_NAME(sys_getegid)
- .long SYMBOL_NAME(sys_setreuid)
- .long SYMBOL_NAME(sys_setregid)
- .long SYMBOL_NAME(sys_getgroups) /* 205 */
- .long SYMBOL_NAME(sys_setgroups)
- .long SYMBOL_NAME(sys_fchown)
- .long SYMBOL_NAME(sys_setresuid)
- .long SYMBOL_NAME(sys_getresuid)
- .long SYMBOL_NAME(sys_setresgid) /* 210 */
- .long SYMBOL_NAME(sys_getresgid)
- .long SYMBOL_NAME(sys_chown)
- .long SYMBOL_NAME(sys_setuid)
- .long SYMBOL_NAME(sys_setgid)
- .long SYMBOL_NAME(sys_setfsuid) /* 215 */
- .long SYMBOL_NAME(sys_setfsgid)
- .long SYMBOL_NAME(sys_pivot_root)
- .long SYMBOL_NAME(sys_mincore)
- .long SYMBOL_NAME(sys_madvise)
- .long SYMBOL_NAME(sys_getdents64) /* 220 */
- .long SYMBOL_NAME(sys_fcntl64)
- .long SYMBOL_NAME(sys_ni_syscall) /* reserved for TUX */
- .long SYMBOL_NAME(sys_ni_syscall) /* Reserved for Security */
- .long SYMBOL_NAME(sys_gettid)
- .long SYMBOL_NAME(sys_readahead) /* 225 */
- .long SYMBOL_NAME(sys_setxattr)
- .long SYMBOL_NAME(sys_lsetxattr)
- .long SYMBOL_NAME(sys_fsetxattr)
- .long SYMBOL_NAME(sys_getxattr)
- .long SYMBOL_NAME(sys_lgetxattr) /* 230 */
- .long SYMBOL_NAME(sys_fgetxattr)
- .long SYMBOL_NAME(sys_listxattr)
- .long SYMBOL_NAME(sys_llistxattr)
- .long SYMBOL_NAME(sys_flistxattr)
- .long SYMBOL_NAME(sys_removexattr) /* 235 */
- .long SYMBOL_NAME(sys_lremovexattr)
- .long SYMBOL_NAME(sys_fremovexattr)
- .long SYMBOL_NAME(sys_tkill)
- .long SYMBOL_NAME(sys_ni_syscall) /* reserved for sendfile64 */
- .long SYMBOL_NAME(sys_ni_syscall) /* 240 reserved for futex */
- .long SYMBOL_NAME(sys_ni_syscall) /* reserved for sched_setaffinity */
- .long SYMBOL_NAME(sys_ni_syscall) /* reserved for sched_getaffinity */
- .long SYMBOL_NAME(sys_ni_syscall) /* sys_set_thread_area */
- .long SYMBOL_NAME(sys_ni_syscall) /* sys_get_thread_area */
- .long SYMBOL_NAME(sys_ni_syscall) /* 245 sys_io_setup */
- .long SYMBOL_NAME(sys_ni_syscall) /* sys_io_destroy */
- .long SYMBOL_NAME(sys_ni_syscall) /* sys_io_getevents */
- .long SYMBOL_NAME(sys_ni_syscall) /* sys_io_submit */
- .long SYMBOL_NAME(sys_ni_syscall) /* sys_io_cancel */
- .long SYMBOL_NAME(sys_ni_syscall) /* 250 sys_alloc_hugepages */
- .long SYMBOL_NAME(sys_ni_syscall) /* sys_free_hugepages */
- .long SYMBOL_NAME(sys_ni_syscall) /* sys_exit_group */
-
- .rept NR_syscalls-(.-sys_call_table)/4
- .long SYMBOL_NAME(sys_ni_syscall)
- .endr
+++ /dev/null
-
-.text
-#include <linux/config.h>
-#include <linux/threads.h>
-#include <linux/linkage.h>
-#include <asm/segment.h>
-#include <asm/page.h>
-#include <asm/pgtable.h>
-#include <asm/desc.h>
-
-/* Offsets in start_info structure */
-#define SHARED_INFO 4
-#define MOD_START 12
-#define MOD_LEN 16
-
-startup_32:
- cld
-
- lss stack_start,%esp
-
- /* Copy initrd somewhere safe before it's clobbered by BSS. */
- mov MOD_LEN(%esi),%ecx
- shr $2,%ecx
- jz 2f /* bail from copy loop if no initrd */
- mov $SYMBOL_NAME(_end),%edi
- add MOD_LEN(%esi),%edi
- mov MOD_START(%esi),%eax
- add MOD_LEN(%esi),%eax
-1: sub $4,%eax
- sub $4,%edi
- mov (%eax),%ebx
- mov %ebx,(%edi)
- loop 1b
- mov %edi,MOD_START(%esi)
-
- /* Clear BSS first so that there are no surprises... */
-2: xorl %eax,%eax
- movl $SYMBOL_NAME(__bss_start),%edi
- movl $SYMBOL_NAME(_end),%ecx
- subl %edi,%ecx
- rep stosb
-
- /* Copy the necessary stuff from start_info structure. */
- /* We need to copy shared_info early, so that sti/cli work */
- mov SHARED_INFO(%esi),%eax
- mov %eax,SYMBOL_NAME(HYPERVISOR_shared_info)
- mov $SYMBOL_NAME(start_info_union),%edi
- mov $128,%ecx
- rep movsl
-
- jmp SYMBOL_NAME(start_kernel)
-
-ENTRY(stack_start)
- .long SYMBOL_NAME(init_task_union)+8192, __KERNEL_DS
-
-.org 0x1000
-ENTRY(empty_zero_page)
-
-.org 0x2000
-ENTRY(default_ldt)
-
-.org 0x3000
-ENTRY(cpu0_pte_quicklist)
-
-.org 0x3400
-ENTRY(cpu0_pgd_quicklist)
-
-.org 0x3800
-ENTRY(stext)
-ENTRY(_stext)
+++ /dev/null
-/******************************************************************************
- * hypervisor.c
- *
- * Communication to/from hypervisor.
- *
- * Copyright (c) 2002, K A Fraser
- */
-
-#include <linux/config.h>
-#include <asm/atomic.h>
-#include <linux/irq.h>
-#include <asm/hypervisor.h>
-#include <asm/system.h>
-#include <asm/ptrace.h>
-
-multicall_entry_t multicall_list[8];
-int nr_multicall_ents = 0;
-
-static unsigned long event_mask = 0;
-
-void frobb(void) {}
-
-void do_hypervisor_callback(struct pt_regs *regs)
-{
- unsigned long events, flags;
- shared_info_t *shared = HYPERVISOR_shared_info;
-
- do {
- /* Specialised local_irq_save(). */
- flags = test_and_clear_bit(EVENTS_MASTER_ENABLE_BIT,
- &shared->events_mask);
- barrier();
-
- events = xchg(&shared->events, 0);
- events &= event_mask;
-
- __asm__ __volatile__ (
- " push %1 ;"
- " sub $4,%%esp ;"
- " jmp 2f ;"
- "1: btrl %%eax,%0 ;" /* clear bit */
- " mov %%eax,(%%esp) ;"
- " call do_IRQ ;" /* do_IRQ(event) */
- "2: bsfl %0,%%eax ;" /* %eax == bit # */
- " jnz 1b ;"
- " add $8,%%esp ;"
- /* we use %ebx because it is callee-saved */
- : : "b" (events), "r" (regs)
- /* clobbered by callback function calls */
- : "eax", "ecx", "edx", "memory" );
-
- /* Specialised local_irq_restore(). */
- if ( flags ) set_bit(EVENTS_MASTER_ENABLE_BIT, &shared->events_mask);
- barrier();
- }
- while ( shared->events );
-}
-
-
-
-/*
- * Define interface to generic handling in irq.c
- */
-
-static void shutdown_hypervisor_event(unsigned int irq)
-{
- clear_bit(irq, &event_mask);
- clear_bit(irq, &HYPERVISOR_shared_info->events_mask);
-}
-
-static void enable_hypervisor_event(unsigned int irq)
-{
- set_bit(irq, &event_mask);
- set_bit(irq, &HYPERVISOR_shared_info->events_mask);
- if ( test_bit(EVENTS_MASTER_ENABLE_BIT,
- &HYPERVISOR_shared_info->events_mask) )
- do_hypervisor_callback(NULL);
-}
-
-static void disable_hypervisor_event(unsigned int irq)
-{
- clear_bit(irq, &event_mask);
- clear_bit(irq, &HYPERVISOR_shared_info->events_mask);
-}
-
-static void ack_hypervisor_event(unsigned int irq)
-{
- if ( !(event_mask & (1<<irq)) )
- {
- printk("Unexpected hypervisor event %d\n", irq);
- atomic_inc(&irq_err_count);
- }
- set_bit(irq, &HYPERVISOR_shared_info->events_mask);
-}
-
-static unsigned int startup_hypervisor_event(unsigned int irq)
-{
- enable_hypervisor_event(irq);
- return 0;
-}
-
-static void end_hypervisor_event(unsigned int irq)
-{
-}
-
-static struct hw_interrupt_type hypervisor_irq_type = {
- "Hypervisor-event",
- startup_hypervisor_event,
- shutdown_hypervisor_event,
- enable_hypervisor_event,
- disable_hypervisor_event,
- ack_hypervisor_event,
- end_hypervisor_event,
- NULL
-};
-
-void __init init_IRQ(void)
-{
- int i;
-
- for ( i = 0; i < NR_IRQS; i++ )
- {
- irq_desc[i].status = IRQ_DISABLED;
- irq_desc[i].action = 0;
- irq_desc[i].depth = 1;
- irq_desc[i].handler = &hypervisor_irq_type;
- }
-}
+++ /dev/null
-#include <linux/config.h>
-#include <linux/module.h>
-#include <linux/smp.h>
-#include <linux/user.h>
-#include <linux/elfcore.h>
-#include <linux/mca.h>
-#include <linux/sched.h>
-#include <linux/in6.h>
-#include <linux/interrupt.h>
-#include <linux/smp_lock.h>
-#include <linux/pm.h>
-//XXX ??? #include <linux/pci.h>
-#include <linux/apm_bios.h>
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/tty.h>
-
-#include <asm/semaphore.h>
-#include <asm/processor.h>
-#include <asm/i387.h>
-#include <asm/uaccess.h>
-#include <asm/checksum.h>
-#include <asm/io.h>
-#include <asm/hardirq.h>
-#include <asm/delay.h>
-#include <asm/irq.h>
-#include <asm/mmx.h>
-#include <asm/desc.h>
-#include <asm/pgtable.h>
-#include <asm/pgalloc.h>
-
-extern void dump_thread(struct pt_regs *, struct user *);
-extern spinlock_t rtc_lock;
-
-#if defined(CONFIG_APMXXX) || defined(CONFIG_APM_MODULEXXX)
-extern void machine_real_restart(unsigned char *, int);
-EXPORT_SYMBOL(machine_real_restart);
-extern void default_idle(void);
-EXPORT_SYMBOL(default_idle);
-#endif
-
-#ifdef CONFIG_SMP
-extern void FASTCALL( __write_lock_failed(rwlock_t *rw));
-extern void FASTCALL( __read_lock_failed(rwlock_t *rw));
-#endif
-
-#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_HD) || defined(CONFIG_BLK_DEV_IDE_MODULE) || defined(CONFIG_BLK_DEV_HD_MODULE)
-extern struct drive_info_struct drive_info;
-EXPORT_SYMBOL(drive_info);
-#endif
-
-// XXX extern unsigned long get_cmos_time(void);
-
-/* platform dependent support */
-EXPORT_SYMBOL(boot_cpu_data);
-EXPORT_SYMBOL(__verify_write);
-EXPORT_SYMBOL(dump_thread);
-EXPORT_SYMBOL(dump_fpu);
-EXPORT_SYMBOL(dump_extended_fpu);
-EXPORT_SYMBOL(enable_irq);
-EXPORT_SYMBOL(disable_irq);
-EXPORT_SYMBOL(disable_irq_nosync);
-EXPORT_SYMBOL(probe_irq_mask);
-EXPORT_SYMBOL(kernel_thread);
-EXPORT_SYMBOL(pm_idle);
-EXPORT_SYMBOL(pm_power_off);
-EXPORT_SYMBOL(apm_info);
-//EXPORT_SYMBOL(gdt);
-EXPORT_SYMBOL(empty_zero_page);
-
-#ifdef CONFIG_DEBUG_IOVIRT
-EXPORT_SYMBOL(__io_virt_debug);
-#endif
-
-EXPORT_SYMBOL_NOVERS(__down_failed);
-EXPORT_SYMBOL_NOVERS(__down_failed_interruptible);
-EXPORT_SYMBOL_NOVERS(__down_failed_trylock);
-EXPORT_SYMBOL_NOVERS(__up_wakeup);
-/* Networking helper routines. */
-EXPORT_SYMBOL(csum_partial_copy_generic);
-/* Delay loops */
-EXPORT_SYMBOL(__udelay);
-EXPORT_SYMBOL(__delay);
-EXPORT_SYMBOL(__const_udelay);
-
-EXPORT_SYMBOL_NOVERS(__get_user_1);
-EXPORT_SYMBOL_NOVERS(__get_user_2);
-EXPORT_SYMBOL_NOVERS(__get_user_4);
-
-EXPORT_SYMBOL(strtok);
-EXPORT_SYMBOL(strpbrk);
-EXPORT_SYMBOL(strstr);
-
-EXPORT_SYMBOL(strncpy_from_user);
-EXPORT_SYMBOL(__strncpy_from_user);
-EXPORT_SYMBOL(clear_user);
-EXPORT_SYMBOL(__clear_user);
-EXPORT_SYMBOL(__generic_copy_from_user);
-EXPORT_SYMBOL(__generic_copy_to_user);
-EXPORT_SYMBOL(strnlen_user);
-
-#ifdef CONFIG_X86_USE_3DNOW
-EXPORT_SYMBOL(_mmx_memcpy);
-EXPORT_SYMBOL(mmx_clear_page);
-EXPORT_SYMBOL(mmx_copy_page);
-#endif
-
-#ifdef CONFIG_SMP
-EXPORT_SYMBOL(cpu_data);
-EXPORT_SYMBOL(kernel_flag_cacheline);
-EXPORT_SYMBOL(smp_num_cpus);
-EXPORT_SYMBOL(cpu_online_map);
-EXPORT_SYMBOL_NOVERS(__write_lock_failed);
-EXPORT_SYMBOL_NOVERS(__read_lock_failed);
-
-/* Global SMP irq stuff */
-EXPORT_SYMBOL(synchronize_irq);
-EXPORT_SYMBOL(global_irq_holder);
-EXPORT_SYMBOL(__global_cli);
-EXPORT_SYMBOL(__global_sti);
-EXPORT_SYMBOL(__global_save_flags);
-EXPORT_SYMBOL(__global_restore_flags);
-EXPORT_SYMBOL(smp_call_function);
-
-/* TLB flushing */
-EXPORT_SYMBOL(flush_tlb_page);
-#endif
-
-#ifdef CONFIG_X86_IO_APIC
-EXPORT_SYMBOL(IO_APIC_get_PCI_irq_vector);
-#endif
-
-#ifdef CONFIG_VT
-EXPORT_SYMBOL(screen_info);
-#endif
-
-EXPORT_SYMBOL(get_wchan);
-
-EXPORT_SYMBOL(rtc_lock);
-
-#undef memcpy
-#undef memset
-extern void * memset(void *,int,__kernel_size_t);
-extern void * memcpy(void *,const void *,__kernel_size_t);
-EXPORT_SYMBOL_NOVERS(memcpy);
-EXPORT_SYMBOL_NOVERS(memset);
-
-#ifdef CONFIG_HAVE_DEC_LOCK
-EXPORT_SYMBOL(atomic_dec_and_lock);
-#endif
-
-#ifdef CONFIG_MULTIQUAD
-EXPORT_SYMBOL(xquad_portio);
-#endif
+++ /dev/null
-#include <linux/sched.h>
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/types.h>
-#include <linux/stddef.h>
-
-
-asmlinkage int sys_ioperm(unsigned long from, unsigned long num, int turn_on)
-{
- /* No IO permission! Selective IO perms aren't virtualised yet. */
- return -EPERM;
-}
-
-
-asmlinkage int sys_iopl(unsigned long unused)
-{
- struct pt_regs *regs = (struct pt_regs *)&unused;
- unsigned int new_io_pl = regs->ebx & 3;
- unsigned int old_io_pl = current->thread.io_pl;
- unsigned int new_hypercall_pl = (regs->ebx >> 2) & 3;
- unsigned int old_hypercall_pl = current->thread.hypercall_pl;
-
- /* Need "raw I/O" privileges for direct port access. */
- if ( (new_io_pl > old_io_pl) &&
- (!capable(CAP_SYS_RAWIO) || !(start_info.flags & SIF_PRIVILEGED)) )
- return -EPERM;
-
- /* Just need generic root/admin privileges for direct hypercall access. */
- if ( (new_hypercall_pl > old_hypercall_pl) && !capable(CAP_SYS_ADMIN) )
- return -EPERM;
-
- /* Maintain OS privileges even if user attempts to relinquish them. */
- if ( new_hypercall_pl == 0 )
- new_hypercall_pl = 1;
- if ( (new_io_pl == 0) && (start_info.flags & SIF_PRIVILEGED) )
- new_io_pl = 1;
-
- /* Change our version of the privilege levels. */
- current->thread.io_pl = new_io_pl;
- current->thread.hypercall_pl = new_hypercall_pl;
-
- /* Force the change at ring 0. */
- HYPERVISOR_set_priv_levels(new_io_pl, new_hypercall_pl);
-
- return 0;
-}
+++ /dev/null
-/*
- * linux/arch/i386/kernel/irq.c
- *
- * Copyright (C) 1992, 1998 Linus Torvalds, Ingo Molnar
- *
- * This file contains the code used by various IRQ handling routines:
- * asking for different IRQ's should be done through these routines
- * instead of just grabbing them. Thus setups with different IRQ numbers
- * shouldn't result in any weird surprises, and installing new handlers
- * should be easier.
- */
-
-/*
- * (mostly architecture independent, will move to kernel/irq.c in 2.5.)
- *
- * IRQs are in fact implemented a bit like signal handlers for the kernel.
- * Naturally it's not a 1:1 relation, but there are similarities.
- */
-
-#include <linux/config.h>
-#include <linux/ptrace.h>
-#include <linux/errno.h>
-#include <linux/signal.h>
-#include <linux/sched.h>
-#include <linux/ioport.h>
-#include <linux/interrupt.h>
-#include <linux/timex.h>
-#include <linux/slab.h>
-#include <linux/random.h>
-#include <linux/smp_lock.h>
-#include <linux/init.h>
-#include <linux/kernel_stat.h>
-#include <linux/irq.h>
-#include <linux/proc_fs.h>
-
-#include <asm/atomic.h>
-#include <asm/io.h>
-#include <asm/smp.h>
-#include <asm/system.h>
-#include <asm/bitops.h>
-#include <asm/uaccess.h>
-#include <asm/pgalloc.h>
-#include <asm/delay.h>
-#include <asm/desc.h>
-#include <asm/irq.h>
-
-
-
-/*
- * Linux has a controller-independent x86 interrupt architecture.
- * every controller has a 'controller-template', that is used
- * by the main code to do the right thing. Each driver-visible
- * interrupt source is transparently wired to the apropriate
- * controller. Thus drivers need not be aware of the
- * interrupt-controller.
- *
- * Various interrupt controllers we handle: 8259 PIC, SMP IO-APIC,
- * PIIX4's internal 8259 PIC and SGI's Visual Workstation Cobalt (IO-)APIC.
- * (IO-APICs assumed to be messaging to Pentium local-APICs)
- *
- * the code is designed to be easily extended with new/different
- * interrupt controllers, without having to do assembly magic.
- */
-
-/*
- * Controller mappings for all interrupt sources:
- */
-irq_desc_t irq_desc[NR_IRQS] __cacheline_aligned =
- { [0 ... NR_IRQS-1] = { 0, &no_irq_type, NULL, 0, SPIN_LOCK_UNLOCKED}};
-
-static void register_irq_proc (unsigned int irq);
-
-/*
- * Special irq handlers.
- */
-
-void no_action(int cpl, void *dev_id, struct pt_regs *regs) { }
-
-/*
- * Generic no controller code
- */
-
-static void enable_none(unsigned int irq) { }
-static unsigned int startup_none(unsigned int irq) { return 0; }
-static void disable_none(unsigned int irq) { }
-static void ack_none(unsigned int irq)
-{
- printk("unexpected IRQ trap at vector %02x\n", irq);
-}
-
-/* startup is the same as "enable", shutdown is same as "disable" */
-#define shutdown_none disable_none
-#define end_none enable_none
-
-struct hw_interrupt_type no_irq_type = {
- "none",
- startup_none,
- shutdown_none,
- enable_none,
- disable_none,
- ack_none,
- end_none
-};
-
-atomic_t irq_err_count;
-#ifdef CONFIG_X86_IO_APIC
-#ifdef APIC_MISMATCH_DEBUG
-atomic_t irq_mis_count;
-#endif
-#endif
-
-/*
- * Generic, controller-independent functions:
- */
-
-int get_irq_list(char *buf)
-{
- int i, j;
- struct irqaction * action;
- char *p = buf;
-
- p += sprintf(p, " ");
- for (j=0; j<smp_num_cpus; j++)
- p += sprintf(p, "CPU%d ",j);
- *p++ = '\n';
-
- for (i = 0 ; i < NR_IRQS ; i++) {
- action = irq_desc[i].action;
- if (!action)
- continue;
- p += sprintf(p, "%3d: ",i);
-#ifndef CONFIG_SMP
- p += sprintf(p, "%10u ", kstat_irqs(i));
-#else
- for (j = 0; j < smp_num_cpus; j++)
- p += sprintf(p, "%10u ",
- kstat.irqs[cpu_logical_map(j)][i]);
-#endif
- p += sprintf(p, " %14s", irq_desc[i].handler->typename);
- p += sprintf(p, " %s", action->name);
-
- for (action=action->next; action; action = action->next)
- p += sprintf(p, ", %s", action->name);
- *p++ = '\n';
- }
- p += sprintf(p, "NMI: ");
- for (j = 0; j < smp_num_cpus; j++)
- p += sprintf(p, "%10u ",
- nmi_count(cpu_logical_map(j)));
- p += sprintf(p, "\n");
-#if CONFIG_X86_LOCAL_APIC
- p += sprintf(p, "LOC: ");
- for (j = 0; j < smp_num_cpus; j++)
- p += sprintf(p, "%10u ",
- apic_timer_irqs[cpu_logical_map(j)]);
- p += sprintf(p, "\n");
-#endif
- p += sprintf(p, "ERR: %10u\n", atomic_read(&irq_err_count));
-#ifdef CONFIG_X86_IO_APIC
-#ifdef APIC_MISMATCH_DEBUG
- p += sprintf(p, "MIS: %10u\n", atomic_read(&irq_mis_count));
-#endif
-#endif
- return p - buf;
-}
-
-
-/*
- * Global interrupt locks for SMP. Allow interrupts to come in on any
- * CPU, yet make cli/sti act globally to protect critical regions..
- */
-
-#ifdef CONFIG_SMP
-unsigned char global_irq_holder = NO_PROC_ID;
-unsigned volatile long global_irq_lock; /* pendantic: long for set_bit --RR */
-
-extern void show_stack(unsigned long* esp);
-
-static void show(char * str)
-{
- int i;
- int cpu = smp_processor_id();
-
- printk("\n%s, CPU %d:\n", str, cpu);
- printk("irq: %d [",irqs_running());
- for(i=0;i < smp_num_cpus;i++)
- printk(" %d",local_irq_count(i));
- printk(" ]\nbh: %d [",spin_is_locked(&global_bh_lock) ? 1 : 0);
- for(i=0;i < smp_num_cpus;i++)
- printk(" %d",local_bh_count(i));
-
- printk(" ]\nStack dumps:");
- for(i = 0; i < smp_num_cpus; i++) {
- unsigned long esp;
- if (i == cpu)
- continue;
- printk("\nCPU %d:",i);
- esp = init_tss[i].esp0;
- if (!esp) {
- /* tss->esp0 is set to NULL in cpu_init(),
- * it's initialized when the cpu returns to user
- * space. -- manfreds
- */
- printk(" <unknown> ");
- continue;
- }
- esp &= ~(THREAD_SIZE-1);
- esp += sizeof(struct task_struct);
- show_stack((void*)esp);
- }
- printk("\nCPU %d:",cpu);
- show_stack(NULL);
- printk("\n");
-}
-
-#define MAXCOUNT 100000000
-
-/*
- * I had a lockup scenario where a tight loop doing
- * spin_unlock()/spin_lock() on CPU#1 was racing with
- * spin_lock() on CPU#0. CPU#0 should have noticed spin_unlock(), but
- * apparently the spin_unlock() information did not make it
- * through to CPU#0 ... nasty, is this by design, do we have to limit
- * 'memory update oscillation frequency' artificially like here?
- *
- * Such 'high frequency update' races can be avoided by careful design, but
- * some of our major constructs like spinlocks use similar techniques,
- * it would be nice to clarify this issue. Set this define to 0 if you
- * want to check whether your system freezes. I suspect the delay done
- * by SYNC_OTHER_CORES() is in correlation with 'snooping latency', but
- * i thought that such things are guaranteed by design, since we use
- * the 'LOCK' prefix.
- */
-#define SUSPECTED_CPU_OR_CHIPSET_BUG_WORKAROUND 0
-
-#if SUSPECTED_CPU_OR_CHIPSET_BUG_WORKAROUND
-# define SYNC_OTHER_CORES(x) udelay(x+1)
-#else
-/*
- * We have to allow irqs to arrive between __sti and __cli
- */
-# define SYNC_OTHER_CORES(x) __asm__ __volatile__ ("nop")
-#endif
-
-static inline void wait_on_irq(int cpu)
-{
- int count = MAXCOUNT;
-
- for (;;) {
-
- /*
- * Wait until all interrupts are gone. Wait
- * for bottom half handlers unless we're
- * already executing in one..
- */
- if (!irqs_running())
- if (local_bh_count(cpu) || !spin_is_locked(&global_bh_lock))
- break;
-
- /* Duh, we have to loop. Release the lock to avoid deadlocks */
- clear_bit(0,&global_irq_lock);
-
- for (;;) {
- if (!--count) {
- show("wait_on_irq");
- count = ~0;
- }
- __sti();
- SYNC_OTHER_CORES(cpu);
- __cli();
- if (irqs_running())
- continue;
- if (global_irq_lock)
- continue;
- if (!local_bh_count(cpu) && spin_is_locked(&global_bh_lock))
- continue;
- if (!test_and_set_bit(0,&global_irq_lock))
- break;
- }
- }
-}
-
-/*
- * This is called when we want to synchronize with
- * interrupts. We may for example tell a device to
- * stop sending interrupts: but to make sure there
- * are no interrupts that are executing on another
- * CPU we need to call this function.
- */
-void synchronize_irq(void)
-{
- if (irqs_running()) {
- /* Stupid approach */
- cli();
- sti();
- }
-}
-
-static inline void get_irqlock(int cpu)
-{
- if (test_and_set_bit(0,&global_irq_lock)) {
- /* do we already hold the lock? */
- if ((unsigned char) cpu == global_irq_holder)
- return;
- /* Uhhuh.. Somebody else got it. Wait.. */
- do {
- do {
- rep_nop();
- } while (test_bit(0,&global_irq_lock));
- } while (test_and_set_bit(0,&global_irq_lock));
- }
- /*
- * We also to make sure that nobody else is running
- * in an interrupt context.
- */
- wait_on_irq(cpu);
-
- /*
- * Ok, finally..
- */
- global_irq_holder = cpu;
-}
-
-void __global_cli(void)
-{
- panic("__global_cli");
-}
-
-void __global_sti(void)
-{
- panic("__global_sti");
-}
-
-/*
- * SMP flags value to restore to:
- * 0 - global cli
- * 1 - global sti
- * 2 - local cli
- * 3 - local sti
- */
-unsigned long __global_save_flags(void)
-{
- panic("__global_save_flags");
-}
-
-void __global_restore_flags(unsigned long flags)
-{
- panic("__global_restore_flags");
-}
-
-#endif
-
-/*
- * This should really return information about whether
- * we should do bottom half handling etc. Right now we
- * end up _always_ checking the bottom half, which is a
- * waste of time and is not what some drivers would
- * prefer.
- */
-int handle_IRQ_event(unsigned int irq, struct pt_regs * regs, struct irqaction * action)
-{
- int status;
- int cpu = smp_processor_id();
-
- irq_enter(cpu, irq);
-
- status = 1; /* Force the "do bottom halves" bit */
-
- if (!(action->flags & SA_INTERRUPT))
- __sti();
-
- do {
- status |= action->flags;
- action->handler(irq, action->dev_id, regs);
- action = action->next;
- } while (action);
- if (status & SA_SAMPLE_RANDOM)
- add_interrupt_randomness(irq);
- __cli();
-
- irq_exit(cpu, irq);
-
- return status;
-}
-
-/*
- * Generic enable/disable code: this just calls
- * down into the PIC-specific version for the actual
- * hardware disable after having gotten the irq
- * controller lock.
- */
-
-/**
- * disable_irq_nosync - disable an irq without waiting
- * @irq: Interrupt to disable
- *
- * Disable the selected interrupt line. Disables and Enables are
- * nested.
- * Unlike disable_irq(), this function does not ensure existing
- * instances of the IRQ handler have completed before returning.
- *
- * This function may be called from IRQ context.
- */
-
-inline void disable_irq_nosync(unsigned int irq)
-{
- irq_desc_t *desc = irq_desc + irq;
- unsigned long flags;
-
- spin_lock_irqsave(&desc->lock, flags);
- if (!desc->depth++) {
- desc->status |= IRQ_DISABLED;
- desc->handler->disable(irq);
- }
- spin_unlock_irqrestore(&desc->lock, flags);
-}
-
-/**
- * disable_irq - disable an irq and wait for completion
- * @irq: Interrupt to disable
- *
- * Disable the selected interrupt line. Enables and Disables are
- * nested.
- * This function waits for any pending IRQ handlers for this interrupt
- * to complete before returning. If you use this function while
- * holding a resource the IRQ handler may need you will deadlock.
- *
- * This function may be called - with care - from IRQ context.
- */
-
-void disable_irq(unsigned int irq)
-{
- disable_irq_nosync(irq);
-
- if (!local_irq_count(smp_processor_id())) {
- do {
- barrier();
- cpu_relax();
- } while (irq_desc[irq].status & IRQ_INPROGRESS);
- }
-}
-
-/**
- * enable_irq - enable handling of an irq
- * @irq: Interrupt to enable
- *
- * Undoes the effect of one call to disable_irq(). If this
- * matches the last disable, processing of interrupts on this
- * IRQ line is re-enabled.
- *
- * This function may be called from IRQ context.
- */
-
-void enable_irq(unsigned int irq)
-{
- irq_desc_t *desc = irq_desc + irq;
- unsigned long flags;
-
- spin_lock_irqsave(&desc->lock, flags);
- switch (desc->depth) {
- case 1: {
- unsigned int status = desc->status & ~IRQ_DISABLED;
- desc->status = status;
- if ((status & (IRQ_PENDING | IRQ_REPLAY)) == IRQ_PENDING) {
- desc->status = status | IRQ_REPLAY;
- hw_resend_irq(desc->handler,irq);
- }
- desc->handler->enable(irq);
- /* fall-through */
- }
- default:
- desc->depth--;
- break;
- case 0:
- printk("enable_irq(%u) unbalanced from %p\n", irq,
- __builtin_return_address(0));
- }
- spin_unlock_irqrestore(&desc->lock, flags);
-}
-
-/*
- * do_IRQ handles all normal device IRQ's (the special
- * SMP cross-CPU interrupts have their own specific
- * handlers).
- */
-asmlinkage unsigned int do_IRQ(int irq, struct pt_regs *regs)
-{
- /*
- * We ack quickly, we don't want the irq controller
- * thinking we're snobs just because some other CPU has
- * disabled global interrupts (we have already done the
- * INT_ACK cycles, it's too late to try to pretend to the
- * controller that we aren't taking the interrupt).
- *
- * 0 return value means that this irq is already being
- * handled by some other CPU. (or is disabled)
- */
- int cpu = smp_processor_id();
- irq_desc_t *desc = irq_desc + irq;
- struct irqaction * action;
- unsigned int status;
-#ifdef CONFIG_DEBUG_STACKOVERFLOW
- long esp;
-
- /* Debugging check for stack overflow: is there less than 1KB free? */
- __asm__ __volatile__("andl %%esp,%0" : "=r" (esp) : "0" (8191));
- if (unlikely(esp < (sizeof(struct task_struct) + 1024))) {
- extern void show_stack(unsigned long *);
-
- printk("do_IRQ: stack overflow: %ld\n",
- esp - sizeof(struct task_struct));
- __asm__ __volatile__("movl %%esp,%0" : "=r" (esp));
- show_stack((void *)esp);
- }
-#endif
-
- kstat.irqs[cpu][irq]++;
- spin_lock(&desc->lock);
- desc->handler->ack(irq);
- /*
- REPLAY is when Linux resends an IRQ that was dropped earlier
- WAITING is used by probe to mark irqs that are being tested
- */
- status = desc->status & ~(IRQ_REPLAY | IRQ_WAITING);
- status |= IRQ_PENDING; /* we _want_ to handle it */
-
- /*
- * If the IRQ is disabled for whatever reason, we cannot
- * use the action we have.
- */
- action = NULL;
- if (!(status & (IRQ_DISABLED | IRQ_INPROGRESS))) {
- action = desc->action;
- status &= ~IRQ_PENDING; /* we commit to handling */
- status |= IRQ_INPROGRESS; /* we are handling it */
- }
- desc->status = status;
-
- /*
- * If there is no IRQ handler or it was disabled, exit early.
- Since we set PENDING, if another processor is handling
- a different instance of this same irq, the other processor
- will take care of it.
- */
- if (!action)
- goto out;
-
- /*
- * Edge triggered interrupts need to remember
- * pending events.
- * This applies to any hw interrupts that allow a second
- * instance of the same irq to arrive while we are in do_IRQ
- * or in the handler. But the code here only handles the _second_
- * instance of the irq, not the third or fourth. So it is mostly
- * useful for irq hardware that does not mask cleanly in an
- * SMP environment.
- */
- for (;;) {
- spin_unlock(&desc->lock);
- handle_IRQ_event(irq, regs, action);
- spin_lock(&desc->lock);
-
- if (!(desc->status & IRQ_PENDING))
- break;
- desc->status &= ~IRQ_PENDING;
- }
- desc->status &= ~IRQ_INPROGRESS;
-out:
- /*
- * The ->end() handler has to deal with interrupts which got
- * disabled while the handler was running.
- */
- desc->handler->end(irq);
- spin_unlock(&desc->lock);
-
- if (softirq_pending(cpu))
- do_softirq();
- return 1;
-}
-
-/**
- * request_irq - allocate an interrupt line
- * @irq: Interrupt line to allocate
- * @handler: Function to be called when the IRQ occurs
- * @irqflags: Interrupt type flags
- * @devname: An ascii name for the claiming device
- * @dev_id: A cookie passed back to the handler function
- *
- * This call allocates interrupt resources and enables the
- * interrupt line and IRQ handling. From the point this
- * call is made your handler function may be invoked. Since
- * your handler function must clear any interrupt the board
- * raises, you must take care both to initialise your hardware
- * and to set up the interrupt handler in the right order.
- *
- * Dev_id must be globally unique. Normally the address of the
- * device data structure is used as the cookie. Since the handler
- * receives this value it makes sense to use it.
- *
- * If your interrupt is shared you must pass a non NULL dev_id
- * as this is required when freeing the interrupt.
- *
- * Flags:
- *
- * SA_SHIRQ Interrupt is shared
- *
- * SA_INTERRUPT Disable local interrupts while processing
- *
- * SA_SAMPLE_RANDOM The interrupt can be used for entropy
- *
- */
-
-int request_irq(unsigned int irq,
- void (*handler)(int, void *, struct pt_regs *),
- unsigned long irqflags,
- const char * devname,
- void *dev_id)
-{
- int retval;
- struct irqaction * action;
-
-#if 1
- /*
- * Sanity-check: shared interrupts should REALLY pass in
- * a real dev-ID, otherwise we'll have trouble later trying
- * to figure out which interrupt is which (messes up the
- * interrupt freeing logic etc).
- */
- if (irqflags & SA_SHIRQ) {
- if (!dev_id)
- printk("Bad boy: %s (at 0x%x) called us without a dev_id!\n", devname, (&irq)[-1]);
- }
-#endif
-
- if (irq >= NR_IRQS)
- return -EINVAL;
- if (!handler)
- return -EINVAL;
-
- action = (struct irqaction *)
- kmalloc(sizeof(struct irqaction), GFP_KERNEL);
- if (!action)
- return -ENOMEM;
-
- action->handler = handler;
- action->flags = irqflags;
- action->mask = 0;
- action->name = devname;
- action->next = NULL;
- action->dev_id = dev_id;
-
- retval = setup_irq(irq, action);
- if (retval)
- kfree(action);
- return retval;
-}
-
-/**
- * free_irq - free an interrupt
- * @irq: Interrupt line to free
- * @dev_id: Device identity to free
- *
- * Remove an interrupt handler. The handler is removed and if the
- * interrupt line is no longer in use by any driver it is disabled.
- * On a shared IRQ the caller must ensure the interrupt is disabled
- * on the card it drives before calling this function. The function
- * does not return until any executing interrupts for this IRQ
- * have completed.
- *
- * This function may be called from interrupt context.
- *
- * Bugs: Attempting to free an irq in a handler for the same irq hangs
- * the machine.
- */
-
-void free_irq(unsigned int irq, void *dev_id)
-{
- irq_desc_t *desc;
- struct irqaction **p;
- unsigned long flags;
-
- if (irq >= NR_IRQS)
- return;
-
- desc = irq_desc + irq;
- spin_lock_irqsave(&desc->lock,flags);
- p = &desc->action;
- for (;;) {
- struct irqaction * action = *p;
- if (action) {
- struct irqaction **pp = p;
- p = &action->next;
- if (action->dev_id != dev_id)
- continue;
-
- /* Found it - now remove it from the list of entries */
- *pp = action->next;
- if (!desc->action) {
- desc->status |= IRQ_DISABLED;
- desc->handler->shutdown(irq);
- }
- spin_unlock_irqrestore(&desc->lock,flags);
-
-#ifdef CONFIG_SMP
- /* Wait to make sure it's not being used on another CPU */
- while (desc->status & IRQ_INPROGRESS) {
- barrier();
- cpu_relax();
- }
-#endif
- kfree(action);
- return;
- }
- printk("Trying to free free IRQ%d\n",irq);
- spin_unlock_irqrestore(&desc->lock,flags);
- return;
- }
-}
-
-/*
- * IRQ autodetection code..
- *
- * This depends on the fact that any interrupt that
- * comes in on to an unassigned handler will get stuck
- * with "IRQ_WAITING" cleared and the interrupt
- * disabled.
- */
-
-static DECLARE_MUTEX(probe_sem);
-
-/**
- * probe_irq_on - begin an interrupt autodetect
- *
- * Commence probing for an interrupt. The interrupts are scanned
- * and a mask of potential interrupt lines is returned.
- *
- */
-
-unsigned long probe_irq_on(void)
-{
- unsigned int i;
- irq_desc_t *desc;
- unsigned long val;
- unsigned long delay;
-
- down(&probe_sem);
- /*
- * something may have generated an irq long ago and we want to
- * flush such a longstanding irq before considering it as spurious.
- */
- for (i = NR_IRQS-1; i > 0; i--) {
- desc = irq_desc + i;
-
- spin_lock_irq(&desc->lock);
- if (!irq_desc[i].action)
- irq_desc[i].handler->startup(i);
- spin_unlock_irq(&desc->lock);
- }
-
- /* Wait for longstanding interrupts to trigger. */
- for (delay = jiffies + HZ/50; time_after(delay, jiffies); )
- /* about 20ms delay */ synchronize_irq();
-
- /*
- * enable any unassigned irqs
- * (we must startup again here because if a longstanding irq
- * happened in the previous stage, it may have masked itself)
- */
- for (i = NR_IRQS-1; i > 0; i--) {
- desc = irq_desc + i;
-
- spin_lock_irq(&desc->lock);
- if (!desc->action) {
- desc->status |= IRQ_AUTODETECT | IRQ_WAITING;
- if (desc->handler->startup(i))
- desc->status |= IRQ_PENDING;
- }
- spin_unlock_irq(&desc->lock);
- }
-
- /*
- * Wait for spurious interrupts to trigger
- */
- for (delay = jiffies + HZ/10; time_after(delay, jiffies); )
- /* about 100ms delay */ synchronize_irq();
-
- /*
- * Now filter out any obviously spurious interrupts
- */
- val = 0;
- for (i = 0; i < NR_IRQS; i++) {
- irq_desc_t *desc = irq_desc + i;
- unsigned int status;
-
- spin_lock_irq(&desc->lock);
- status = desc->status;
-
- if (status & IRQ_AUTODETECT) {
- /* It triggered already - consider it spurious. */
- if (!(status & IRQ_WAITING)) {
- desc->status = status & ~IRQ_AUTODETECT;
- desc->handler->shutdown(i);
- } else
- if (i < 32)
- val |= 1 << i;
- }
- spin_unlock_irq(&desc->lock);
- }
-
- return val;
-}
-
-/*
- * Return a mask of triggered interrupts (this
- * can handle only legacy ISA interrupts).
- */
-
-/**
- * probe_irq_mask - scan a bitmap of interrupt lines
- * @val: mask of interrupts to consider
- *
- * Scan the ISA bus interrupt lines and return a bitmap of
- * active interrupts. The interrupt probe logic state is then
- * returned to its previous value.
- *
- * Note: we need to scan all the irq's even though we will
- * only return ISA irq numbers - just so that we reset them
- * all to a known state.
- */
-unsigned int probe_irq_mask(unsigned long val)
-{
- int i;
- unsigned int mask;
-
- mask = 0;
- for (i = 0; i < NR_IRQS; i++) {
- irq_desc_t *desc = irq_desc + i;
- unsigned int status;
-
- spin_lock_irq(&desc->lock);
- status = desc->status;
-
- if (status & IRQ_AUTODETECT) {
- if (i < 16 && !(status & IRQ_WAITING))
- mask |= 1 << i;
-
- desc->status = status & ~IRQ_AUTODETECT;
- desc->handler->shutdown(i);
- }
- spin_unlock_irq(&desc->lock);
- }
- up(&probe_sem);
-
- return mask & val;
-}
-
-/*
- * Return the one interrupt that triggered (this can
- * handle any interrupt source).
- */
-
-/**
- * probe_irq_off - end an interrupt autodetect
- * @val: mask of potential interrupts (unused)
- *
- * Scans the unused interrupt lines and returns the line which
- * appears to have triggered the interrupt. If no interrupt was
- * found then zero is returned. If more than one interrupt is
- * found then minus the first candidate is returned to indicate
- * their is doubt.
- *
- * The interrupt probe logic state is returned to its previous
- * value.
- *
- * BUGS: When used in a module (which arguably shouldnt happen)
- * nothing prevents two IRQ probe callers from overlapping. The
- * results of this are non-optimal.
- */
-
-int probe_irq_off(unsigned long val)
-{
- int i, irq_found, nr_irqs;
-
- nr_irqs = 0;
- irq_found = 0;
- for (i = 0; i < NR_IRQS; i++) {
- irq_desc_t *desc = irq_desc + i;
- unsigned int status;
-
- spin_lock_irq(&desc->lock);
- status = desc->status;
-
- if (status & IRQ_AUTODETECT) {
- if (!(status & IRQ_WAITING)) {
- if (!nr_irqs)
- irq_found = i;
- nr_irqs++;
- }
- desc->status = status & ~IRQ_AUTODETECT;
- desc->handler->shutdown(i);
- }
- spin_unlock_irq(&desc->lock);
- }
- up(&probe_sem);
-
- if (nr_irqs > 1)
- irq_found = -irq_found;
- return irq_found;
-}
-
-/* this was setup_x86_irq but it seems pretty generic */
-int setup_irq(unsigned int irq, struct irqaction * new)
-{
- int shared = 0;
- unsigned long flags;
- struct irqaction *old, **p;
- irq_desc_t *desc = irq_desc + irq;
-
- /*
- * Some drivers like serial.c use request_irq() heavily,
- * so we have to be careful not to interfere with a
- * running system.
- */
- if (new->flags & SA_SAMPLE_RANDOM) {
- /*
- * This function might sleep, we want to call it first,
- * outside of the atomic block.
- * Yes, this might clear the entropy pool if the wrong
- * driver is attempted to be loaded, without actually
- * installing a new handler, but is this really a problem,
- * only the sysadmin is able to do this.
- */
- rand_initialize_irq(irq);
- }
-
- /*
- * The following block of code has to be executed atomically
- */
- spin_lock_irqsave(&desc->lock,flags);
- p = &desc->action;
- if ((old = *p) != NULL) {
- /* Can't share interrupts unless both agree to */
- if (!(old->flags & new->flags & SA_SHIRQ)) {
- spin_unlock_irqrestore(&desc->lock,flags);
- return -EBUSY;
- }
-
- /* add new interrupt at end of irq queue */
- do {
- p = &old->next;
- old = *p;
- } while (old);
- shared = 1;
- }
-
- *p = new;
-
- if (!shared) {
- desc->depth = 0;
- desc->status &= ~(IRQ_DISABLED | IRQ_AUTODETECT | IRQ_WAITING);
- desc->handler->startup(irq);
- }
- spin_unlock_irqrestore(&desc->lock,flags);
-
- register_irq_proc(irq);
- return 0;
-}
-
-static struct proc_dir_entry * root_irq_dir;
-static struct proc_dir_entry * irq_dir [NR_IRQS];
-
-#define HEX_DIGITS 8
-
-static unsigned int parse_hex_value (const char *buffer,
- unsigned long count, unsigned long *ret)
-{
- unsigned char hexnum [HEX_DIGITS];
- unsigned long value;
- int i;
-
- if (!count)
- return -EINVAL;
- if (count > HEX_DIGITS)
- count = HEX_DIGITS;
- if (copy_from_user(hexnum, buffer, count))
- return -EFAULT;
-
- /*
- * Parse the first 8 characters as a hex string, any non-hex char
- * is end-of-string. '00e1', 'e1', '00E1', 'E1' are all the same.
- */
- value = 0;
-
- for (i = 0; i < count; i++) {
- unsigned int c = hexnum[i];
-
- switch (c) {
- case '0' ... '9': c -= '0'; break;
- case 'a' ... 'f': c -= 'a'-10; break;
- case 'A' ... 'F': c -= 'A'-10; break;
- default:
- goto out;
- }
- value = (value << 4) | c;
- }
-out:
- *ret = value;
- return 0;
-}
-
-#if CONFIG_SMP
-
-static struct proc_dir_entry * smp_affinity_entry [NR_IRQS];
-
-static unsigned long irq_affinity [NR_IRQS] = { [0 ... NR_IRQS-1] = ~0UL };
-static int irq_affinity_read_proc (char *page, char **start, off_t off,
- int count, int *eof, void *data)
-{
- if (count < HEX_DIGITS+1)
- return -EINVAL;
- return sprintf (page, "%08lx\n", irq_affinity[(long)data]);
-}
-
-static int irq_affinity_write_proc (struct file *file, const char *buffer,
- unsigned long count, void *data)
-{
- int irq = (long) data, full_count = count, err;
- unsigned long new_value;
-
- if (!irq_desc[irq].handler->set_affinity)
- return -EIO;
-
- err = parse_hex_value(buffer, count, &new_value);
-
- /*
- * Do not allow disabling IRQs completely - it's a too easy
- * way to make the system unusable accidentally :-) At least
- * one online CPU still has to be targeted.
- */
- if (!(new_value & cpu_online_map))
- return -EINVAL;
-
- irq_affinity[irq] = new_value;
- irq_desc[irq].handler->set_affinity(irq, new_value);
-
- return full_count;
-}
-
-#endif
-
-static int prof_cpu_mask_read_proc (char *page, char **start, off_t off,
- int count, int *eof, void *data)
-{
- unsigned long *mask = (unsigned long *) data;
- if (count < HEX_DIGITS+1)
- return -EINVAL;
- return sprintf (page, "%08lx\n", *mask);
-}
-
-static int prof_cpu_mask_write_proc (struct file *file, const char *buffer,
- unsigned long count, void *data)
-{
- unsigned long *mask = (unsigned long *) data, full_count = count, err;
- unsigned long new_value;
-
- err = parse_hex_value(buffer, count, &new_value);
- if (err)
- return err;
-
- *mask = new_value;
- return full_count;
-}
-
-#define MAX_NAMELEN 10
-
-static void register_irq_proc (unsigned int irq)
-{
- char name [MAX_NAMELEN];
-
- if (!root_irq_dir || (irq_desc[irq].handler == &no_irq_type) ||
- irq_dir[irq])
- return;
-
- memset(name, 0, MAX_NAMELEN);
- sprintf(name, "%d", irq);
-
- /* create /proc/irq/1234 */
- irq_dir[irq] = proc_mkdir(name, root_irq_dir);
-
-#if CONFIG_SMP
- {
- struct proc_dir_entry *entry;
-
- /* create /proc/irq/1234/smp_affinity */
- entry = create_proc_entry("smp_affinity", 0600, irq_dir[irq]);
-
- if (entry) {
- entry->nlink = 1;
- entry->data = (void *)(long)irq;
- entry->read_proc = irq_affinity_read_proc;
- entry->write_proc = irq_affinity_write_proc;
- }
-
- smp_affinity_entry[irq] = entry;
- }
-#endif
-}
-
-unsigned long prof_cpu_mask = -1;
-
-void init_irq_proc (void)
-{
- struct proc_dir_entry *entry;
- int i;
-
- /* create /proc/irq */
- root_irq_dir = proc_mkdir("irq", 0);
-
- /* create /proc/irq/prof_cpu_mask */
- entry = create_proc_entry("prof_cpu_mask", 0600, root_irq_dir);
-
- if (!entry)
- return;
-
- entry->nlink = 1;
- entry->data = (void *)&prof_cpu_mask;
- entry->read_proc = prof_cpu_mask_read_proc;
- entry->write_proc = prof_cpu_mask_write_proc;
-
- /*
- * Create entries for all existing IRQs.
- */
- for (i = 0; i < NR_IRQS; i++)
- register_irq_proc(i);
-}
-
+++ /dev/null
-/*
- * linux/kernel/ldt.c
- *
- * Copyright (C) 1992 Krishna Balasubramanian and Linus Torvalds
- * Copyright (C) 1999 Ingo Molnar <mingo@redhat.com>
- */
-
-#include <linux/errno.h>
-#include <linux/sched.h>
-#include <linux/string.h>
-#include <linux/mm.h>
-#include <linux/smp.h>
-#include <linux/smp_lock.h>
-#include <linux/vmalloc.h>
-
-#include <asm/uaccess.h>
-#include <asm/system.h>
-#include <asm/ldt.h>
-#include <asm/desc.h>
-
-/*
- * read_ldt() is not really atomic - this is not a problem since
- * synchronization of reads and writes done to the LDT has to be
- * assured by user-space anyway. Writes are atomic, to protect
- * the security checks done on new descriptors.
- */
-static int read_ldt(void * ptr, unsigned long bytecount)
-{
- int err;
- unsigned long size;
- struct mm_struct * mm = current->mm;
-
- err = 0;
- if (!mm->context.segments)
- goto out;
-
- size = LDT_ENTRIES*LDT_ENTRY_SIZE;
- if (size > bytecount)
- size = bytecount;
-
- err = size;
- if (copy_to_user(ptr, mm->context.segments, size))
- err = -EFAULT;
- out:
- return err;
-}
-
-static int read_default_ldt(void * ptr, unsigned long bytecount)
-{
- int err;
- unsigned long size;
- void *address;
-
- err = 0;
- address = &default_ldt[0];
- size = sizeof(struct desc_struct);
- if (size > bytecount)
- size = bytecount;
-
- err = size;
- if (copy_to_user(ptr, address, size))
- err = -EFAULT;
-
- return err;
-}
-
-static int write_ldt(void * ptr, unsigned long bytecount, int oldmode)
-{
- struct mm_struct * mm = current->mm;
- __u32 entry_1, entry_2, *lp;
- unsigned long phys_lp;
- int error;
- struct modify_ldt_ldt_s ldt_info;
-
- error = -EINVAL;
- if (bytecount != sizeof(ldt_info))
- goto out;
- error = -EFAULT;
- if (copy_from_user(&ldt_info, ptr, sizeof(ldt_info)))
- goto out;
-
- error = -EINVAL;
- if (ldt_info.entry_number >= LDT_ENTRIES)
- goto out;
- if (ldt_info.contents == 3) {
- if (oldmode)
- goto out;
- if (ldt_info.seg_not_present == 0)
- goto out;
- }
-
- down_write(&mm->mmap_sem);
- if (!mm->context.segments) {
- void * segments = vmalloc(LDT_ENTRIES*LDT_ENTRY_SIZE);
- error = -ENOMEM;
- if (!segments)
- goto out_unlock;
- memset(segments, 0, LDT_ENTRIES*LDT_ENTRY_SIZE);
- make_pages_readonly(segments, (LDT_ENTRIES*LDT_ENTRY_SIZE)/PAGE_SIZE);
- wmb();
- mm->context.segments = segments;
- mm->context.cpuvalid = 1UL << smp_processor_id();
- load_LDT(mm);
- flush_page_update_queue();
- }
-
- lp = (__u32 *)((ldt_info.entry_number<<3) + (char *)mm->context.segments);
- phys_lp = arbitrary_virt_to_phys(lp);
-
- /* Allow LDTs to be cleared by the user. */
- if (ldt_info.base_addr == 0 && ldt_info.limit == 0) {
- if (oldmode ||
- (ldt_info.contents == 0 &&
- ldt_info.read_exec_only == 1 &&
- ldt_info.seg_32bit == 0 &&
- ldt_info.limit_in_pages == 0 &&
- ldt_info.seg_not_present == 1 &&
- ldt_info.useable == 0 )) {
- entry_1 = 0;
- entry_2 = 0;
- goto install;
- }
- }
-
- entry_1 = ((ldt_info.base_addr & 0x0000ffff) << 16) |
- (ldt_info.limit & 0x0ffff);
- entry_2 = (ldt_info.base_addr & 0xff000000) |
- ((ldt_info.base_addr & 0x00ff0000) >> 16) |
- (ldt_info.limit & 0xf0000) |
- ((ldt_info.read_exec_only ^ 1) << 9) |
- (ldt_info.contents << 10) |
- ((ldt_info.seg_not_present ^ 1) << 15) |
- (ldt_info.seg_32bit << 22) |
- (ldt_info.limit_in_pages << 23) |
- 0x7000;
- if (!oldmode)
- entry_2 |= (ldt_info.useable << 20);
-
- /* Install the new entry ... */
- install:
- HYPERVISOR_update_descriptor(phys_lp, entry_1, entry_2);
- error = 0;
-
- out_unlock:
- up_write(&mm->mmap_sem);
- out:
- return error;
-}
-
-asmlinkage int sys_modify_ldt(int func, void *ptr, unsigned long bytecount)
-{
- int ret = -ENOSYS;
-
- switch (func) {
- case 0:
- ret = read_ldt(ptr, bytecount);
- break;
- case 1:
- ret = write_ldt(ptr, bytecount, 1);
- break;
- case 2:
- ret = read_default_ldt(ptr, bytecount);
- break;
- case 0x11:
- ret = write_ldt(ptr, bytecount, 0);
- break;
- }
- return ret;
-}
+++ /dev/null
-/*
- * linux/arch/i386/kernel/process.c
- *
- * Copyright (C) 1995 Linus Torvalds
- *
- * Pentium III FXSR, SSE support
- * Gareth Hughes <gareth@valinux.com>, May 2000
- */
-
-/*
- * This file handles the architecture-dependent parts of process handling..
- */
-
-#define __KERNEL_SYSCALLS__
-#include <stdarg.h>
-
-#include <linux/errno.h>
-#include <linux/sched.h>
-#include <linux/kernel.h>
-#include <linux/mm.h>
-#include <linux/smp.h>
-#include <linux/smp_lock.h>
-#include <linux/stddef.h>
-#include <linux/unistd.h>
-#include <linux/ptrace.h>
-#include <linux/slab.h>
-#include <linux/vmalloc.h>
-#include <linux/user.h>
-#include <linux/a.out.h>
-#include <linux/interrupt.h>
-#include <linux/config.h>
-#include <linux/delay.h>
-#include <linux/reboot.h>
-#include <linux/init.h>
-#include <linux/mc146818rtc.h>
-
-#include <asm/uaccess.h>
-#include <asm/pgtable.h>
-#include <asm/system.h>
-#include <asm/io.h>
-#include <asm/ldt.h>
-#include <asm/processor.h>
-#include <asm/i387.h>
-#include <asm/desc.h>
-#include <asm/mmu_context.h>
-#include <asm/multicall.h>
-
-#include <linux/irq.h>
-
-asmlinkage void ret_from_fork(void) __asm__("ret_from_fork");
-
-int hlt_counter;
-
-/*
- * Powermanagement idle function, if any..
- */
-void (*pm_idle)(void);
-
-/*
- * Power off function, if any
- */
-void (*pm_power_off)(void);
-
-void disable_hlt(void)
-{
- hlt_counter++;
-}
-
-void enable_hlt(void)
-{
- hlt_counter--;
-}
-
-/*
- * The idle thread. There's no useful work to be
- * done, so just try to conserve power and have a
- * low exit latency (ie sit in a loop waiting for
- * somebody to say that they'd like to reschedule)
- */
-void cpu_idle (void)
-{
- /* endless idle loop with no priority at all */
- init_idle();
- current->nice = 20;
- current->counter = -100;
-
- while (1) {
- while (!current->need_resched)
- HYPERVISOR_yield();
- schedule();
- check_pgt_cache();
- }
-}
-
-void machine_restart(char * __unused)
-{
- HYPERVISOR_exit();
-}
-
-void machine_halt(void)
-{
- HYPERVISOR_exit();
-}
-
-void machine_power_off(void)
-{
- HYPERVISOR_exit();
-}
-
-extern void show_trace(unsigned long* esp);
-
-void show_regs(struct pt_regs * regs)
-{
- printk("\n");
- printk("Pid: %d, comm: %20s\n", current->pid, current->comm);
- printk("EIP: %04x:[<%08lx>] CPU: %d",0xffff & regs->xcs,regs->eip, smp_processor_id());
- if (regs->xcs & 2)
- printk(" ESP: %04x:%08lx",0xffff & regs->xss,regs->esp);
- printk(" EFLAGS: %08lx %s\n",regs->eflags, print_tainted());
- printk("EAX: %08lx EBX: %08lx ECX: %08lx EDX: %08lx\n",
- regs->eax,regs->ebx,regs->ecx,regs->edx);
- printk("ESI: %08lx EDI: %08lx EBP: %08lx",
- regs->esi, regs->edi, regs->ebp);
- printk(" DS: %04x ES: %04x\n",
- 0xffff & regs->xds,0xffff & regs->xes);
-
- show_trace(®s->esp);
-}
-
-/*
- * No need to lock the MM as we are the last user
- */
-void release_segments(struct mm_struct *mm)
-{
- void * ldt = mm->context.segments;
-
- /*
- * free the LDT
- */
- if (ldt) {
- mm->context.segments = NULL;
- clear_LDT();
- make_pages_writeable(ldt, (LDT_ENTRIES*LDT_ENTRY_SIZE)/PAGE_SIZE);
- flush_page_update_queue();
- vfree(ldt);
- }
-}
-
-/*
- * Create a kernel thread
- */
-int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
-{
- long retval, d0;
-
- __asm__ __volatile__(
- "movl %%esp,%%esi\n\t"
- "int $0x80\n\t" /* Linux/i386 system call */
- "cmpl %%esp,%%esi\n\t" /* child or parent? */
- "je 1f\n\t" /* parent - jump */
- /* Load the argument into eax, and push it. That way, it does
- * not matter whether the called function is compiled with
- * -mregparm or not. */
- "movl %4,%%eax\n\t"
- "pushl %%eax\n\t"
- "call *%5\n\t" /* call fn */
- "movl %3,%0\n\t" /* exit */
- "int $0x80\n"
- "1:\t"
- :"=&a" (retval), "=&S" (d0)
- :"0" (__NR_clone), "i" (__NR_exit),
- "r" (arg), "r" (fn),
- "b" (flags | CLONE_VM)
- : "memory");
-
- return retval;
-}
-
-/*
- * Free current thread data structures etc..
- */
-void exit_thread(void)
-{
- /* nothing to do ... */
-}
-
-void flush_thread(void)
-{
- struct task_struct *tsk = current;
-
- memset(tsk->thread.debugreg, 0, sizeof(unsigned long)*8);
-
- /*
- * Forget coprocessor state..
- */
- clear_fpu(tsk);
- tsk->used_math = 0;
-}
-
-void release_thread(struct task_struct *dead_task)
-{
- if (dead_task->mm) {
- void * ldt = dead_task->mm->context.segments;
-
- // temporary debugging check
- if (ldt) {
- printk("WARNING: dead process %8s still has LDT? <%p>\n",
- dead_task->comm, ldt);
- BUG();
- }
- }
-}
-
-/*
- * we do not have to muck with descriptors here, that is
- * done in switch_mm() as needed.
- */
-void copy_segments(struct task_struct *p, struct mm_struct *new_mm)
-{
- struct mm_struct * old_mm;
- void *old_ldt, *ldt;
-
- ldt = NULL;
- old_mm = current->mm;
- if (old_mm && (old_ldt = old_mm->context.segments) != NULL) {
- /*
- * Completely new LDT, we initialize it from the parent:
- */
- ldt = vmalloc(LDT_ENTRIES*LDT_ENTRY_SIZE);
- if ( ldt == NULL )
- {
- printk(KERN_WARNING "ldt allocation failed\n");
- }
- else
- {
- memcpy(ldt, old_ldt, LDT_ENTRIES*LDT_ENTRY_SIZE);
- make_pages_readonly(ldt, (LDT_ENTRIES*LDT_ENTRY_SIZE)/PAGE_SIZE);
- }
- }
- new_mm->context.segments = ldt;
- new_mm->context.cpuvalid = ~0UL; /* valid on all CPU's - they can't have stale data */
-}
-
-/*
- * Save a segment.
- */
-#define savesegment(seg,value) \
- asm volatile("movl %%" #seg ",%0":"=m" (*(int *)&(value)))
-
-int copy_thread(int nr, unsigned long clone_flags, unsigned long esp,
- unsigned long unused,
- struct task_struct * p, struct pt_regs * regs)
-{
- struct pt_regs * childregs;
- unsigned long eflags;
-
- childregs = ((struct pt_regs *) (THREAD_SIZE + (unsigned long) p)) - 1;
- struct_cpy(childregs, regs);
- childregs->eax = 0;
- childregs->esp = esp;
-
- p->thread.esp = (unsigned long) childregs;
- p->thread.esp0 = (unsigned long) (childregs+1);
-
- p->thread.eip = (unsigned long) ret_from_fork;
-
- savesegment(fs,p->thread.fs);
- savesegment(gs,p->thread.gs);
-
- unlazy_fpu(current);
- struct_cpy(&p->thread.i387, ¤t->thread.i387);
-
-
- __asm__ __volatile__ ( "pushfl; popl %0" : "=r" (eflags) : );
- p->thread.io_pl = (eflags >> 12) & 3;
-
- /* We're careful with hypercall privileges. Don't allow inheritance. */
- p->thread.hypercall_pl = 1;
-
- return 0;
-}
-
-/*
- * fill in the user structure for a core dump..
- */
-void dump_thread(struct pt_regs * regs, struct user * dump)
-{
- int i;
-
-/* changed the size calculations - should hopefully work better. lbt */
- dump->magic = CMAGIC;
- dump->start_code = 0;
- dump->start_stack = regs->esp & ~(PAGE_SIZE - 1);
- dump->u_tsize = ((unsigned long) current->mm->end_code) >> PAGE_SHIFT;
- dump->u_dsize = ((unsigned long) (current->mm->brk + (PAGE_SIZE-1))) >> PAGE_SHIFT;
- dump->u_dsize -= dump->u_tsize;
- dump->u_ssize = 0;
- for (i = 0; i < 8; i++)
- dump->u_debugreg[i] = current->thread.debugreg[i];
-
- if (dump->start_stack < TASK_SIZE)
- dump->u_ssize = ((unsigned long) (TASK_SIZE - dump->start_stack)) >> PAGE_SHIFT;
-
- dump->regs.ebx = regs->ebx;
- dump->regs.ecx = regs->ecx;
- dump->regs.edx = regs->edx;
- dump->regs.esi = regs->esi;
- dump->regs.edi = regs->edi;
- dump->regs.ebp = regs->ebp;
- dump->regs.eax = regs->eax;
- dump->regs.ds = regs->xds;
- dump->regs.es = regs->xes;
- savesegment(fs,dump->regs.fs);
- savesegment(gs,dump->regs.gs);
- dump->regs.orig_eax = regs->orig_eax;
- dump->regs.eip = regs->eip;
- dump->regs.cs = regs->xcs;
- dump->regs.eflags = regs->eflags;
- dump->regs.esp = regs->esp;
- dump->regs.ss = regs->xss;
-
- dump->u_fpvalid = dump_fpu (regs, &dump->i387);
-}
-
-/*
- * switch_to(x,yn) should switch tasks from x to y.
- *
- * We fsave/fwait so that an exception goes off at the right time
- * (as a call from the fsave or fwait in effect) rather than to
- * the wrong process. Lazy FP saving no longer makes any sense
- * with modern CPU's, and this simplifies a lot of things (SMP
- * and UP become the same).
- *
- * NOTE! We used to use the x86 hardware context switching. The
- * reason for not using it any more becomes apparent when you
- * try to recover gracefully from saved state that is no longer
- * valid (stale segment register values in particular). With the
- * hardware task-switch, there is no way to fix up bad state in
- * a reasonable manner.
- *
- * The fact that Intel documents the hardware task-switching to
- * be slow is a fairly red herring - this code is not noticeably
- * faster. However, there _is_ some room for improvement here,
- * so the performance issues may eventually be a valid point.
- * More important, however, is the fact that this allows us much
- * more flexibility.
- */
-void __switch_to(struct task_struct *prev_p, struct task_struct *next_p)
-{
- struct thread_struct *prev = &prev_p->thread,
- *next = &next_p->thread;
-
- __cli();
-
- MULTICALL_flush_page_update_queue();
-
- /*
- * This is basically 'unlazy_fpu', except that we queue a multicall to
- * indicate FPU task switch, rather than synchronously trapping to Xen.
- */
- if ( prev_p->flags & PF_USEDFPU )
- {
- if ( cpu_has_fxsr )
- asm volatile( "fxsave %0 ; fnclex"
- : "=m" (prev_p->thread.i387.fxsave) );
- else
- asm volatile( "fnsave %0 ; fwait"
- : "=m" (prev_p->thread.i387.fsave) );
- prev_p->flags &= ~PF_USEDFPU;
- queue_multicall0(__HYPERVISOR_fpu_taskswitch);
- }
-
- queue_multicall2(__HYPERVISOR_stack_switch, __KERNEL_DS, next->esp0);
- /* Next call will silently fail if we are a non-privileged guest OS. */
- queue_multicall2(__HYPERVISOR_set_priv_levels,
- next->io_pl, next->hypercall_pl);
-
- /* EXECUTE ALL TASK SWITCH XEN SYSCALLS AT THIS POINT. */
- execute_multicall_list();
- __sti();
-
- /*
- * Restore %fs and %gs.
- */
- loadsegment(fs, next->fs);
- loadsegment(gs, next->gs);
-
- /*
- * Now maybe reload the debug registers
- */
- if ( next->debugreg[7] != 0 )
- {
- HYPERVISOR_set_debugreg(0, next->debugreg[0]);
- HYPERVISOR_set_debugreg(1, next->debugreg[1]);
- HYPERVISOR_set_debugreg(2, next->debugreg[2]);
- HYPERVISOR_set_debugreg(3, next->debugreg[3]);
- /* no 4 and 5 */
- HYPERVISOR_set_debugreg(6, next->debugreg[6]);
- HYPERVISOR_set_debugreg(7, next->debugreg[7]);
- }
-}
-
-asmlinkage int sys_fork(struct pt_regs regs)
-{
- return do_fork(SIGCHLD, regs.esp, ®s, 0);
-}
-
-asmlinkage int sys_clone(struct pt_regs regs)
-{
- unsigned long clone_flags;
- unsigned long newsp;
-
- clone_flags = regs.ebx;
- newsp = regs.ecx;
- if (!newsp)
- newsp = regs.esp;
- return do_fork(clone_flags, newsp, ®s, 0);
-}
-
-/*
- * This is trivial, and on the face of it looks like it
- * could equally well be done in user mode.
- *
- * Not so, for quite unobvious reasons - register pressure.
- * In user mode vfork() cannot have a stack frame, and if
- * done by calling the "clone()" system call directly, you
- * do not have enough call-clobbered registers to hold all
- * the information you need.
- */
-asmlinkage int sys_vfork(struct pt_regs regs)
-{
- return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs.esp, ®s, 0);
-}
-
-/*
- * sys_execve() executes a new program.
- */
-asmlinkage int sys_execve(struct pt_regs regs)
-{
- int error;
- char * filename;
-
- filename = getname((char *) regs.ebx);
- error = PTR_ERR(filename);
- if (IS_ERR(filename))
- goto out;
- error = do_execve(filename, (char **) regs.ecx, (char **) regs.edx, ®s);
- if (error == 0)
- current->ptrace &= ~PT_DTRACE;
- putname(filename);
- out:
- return error;
-}
-
-/*
- * These bracket the sleeping functions..
- */
-extern void scheduling_functions_start_here(void);
-extern void scheduling_functions_end_here(void);
-#define first_sched ((unsigned long) scheduling_functions_start_here)
-#define last_sched ((unsigned long) scheduling_functions_end_here)
-
-unsigned long get_wchan(struct task_struct *p)
-{
- unsigned long ebp, esp, eip;
- unsigned long stack_page;
- int count = 0;
- if (!p || p == current || p->state == TASK_RUNNING)
- return 0;
- stack_page = (unsigned long)p;
- esp = p->thread.esp;
- if (!stack_page || esp < stack_page || esp > 8188+stack_page)
- return 0;
- /* include/asm-i386/system.h:switch_to() pushes ebp last. */
- ebp = *(unsigned long *) esp;
- do {
- if (ebp < stack_page || ebp > 8184+stack_page)
- return 0;
- eip = *(unsigned long *) (ebp+4);
- if (eip < first_sched || eip >= last_sched)
- return eip;
- ebp = *(unsigned long *) ebp;
- } while (count++ < 16);
- return 0;
-}
-#undef last_sched
-#undef first_sched
+++ /dev/null
-/*
- * linux/arch/i386/kernel/setup.c
- *
- * Copyright (C) 1995 Linus Torvalds
- */
-
-/*
- * This file handles the architecture-dependent parts of initialization
- */
-
-#include <linux/errno.h>
-#include <linux/sched.h>
-#include <linux/kernel.h>
-#include <linux/mm.h>
-#include <linux/stddef.h>
-#include <linux/unistd.h>
-#include <linux/ptrace.h>
-#include <linux/slab.h>
-#include <linux/user.h>
-#include <linux/a.out.h>
-#include <linux/tty.h>
-#include <linux/ioport.h>
-#include <linux/delay.h>
-#include <linux/config.h>
-#include <linux/init.h>
-#include <linux/apm_bios.h>
-#ifdef CONFIG_BLK_DEV_RAM
-#include <linux/blk.h>
-#endif
-#include <linux/highmem.h>
-#include <linux/bootmem.h>
-#include <linux/seq_file.h>
-#include <asm/processor.h>
-#include <linux/console.h>
-#include <asm/mtrr.h>
-#include <asm/uaccess.h>
-#include <asm/system.h>
-#include <asm/io.h>
-#include <asm/smp.h>
-#include <asm/msr.h>
-#include <asm/desc.h>
-#include <asm/dma.h>
-#include <asm/mpspec.h>
-#include <asm/mmu_context.h>
-#include <asm/hypervisor.h>
-
-shared_info_t *HYPERVISOR_shared_info;
-
-unsigned long *phys_to_machine_mapping;
-
-/*
- * Machine setup..
- */
-
-char ignore_irq13; /* set if exception 16 works */
-struct cpuinfo_x86 boot_cpu_data = { 0, 0, 0, 0, -1, 1, 0, 0, -1 };
-
-unsigned long mmu_cr4_features;
-
-/*
- * Bus types ..
- */
-#ifdef CONFIG_EISA
-int EISA_bus;
-#endif
-int MCA_bus;
-
-/* for MCA, but anyone else can use it if they want */
-unsigned int machine_id;
-unsigned int machine_submodel_id;
-unsigned int BIOS_revision;
-unsigned int mca_pentium_flag;
-
-/* For PCI or other memory-mapped resources */
-unsigned long pci_mem_start = 0x10000000;
-
-/*
- * Setup options
- */
-struct drive_info_struct { char dummy[32]; } drive_info;
-struct screen_info screen_info;
-struct apm_info apm_info;
-struct sys_desc_table_struct {
- unsigned short length;
- unsigned char table[0];
-};
-
-unsigned char aux_device_present;
-
-extern int root_mountflags;
-extern char _text, _etext, _edata, _end;
-
-int enable_acpi_smp_table;
-
-/* Raw start-of-day parameters from the hypervisor. */
-union start_info_union start_info_union;
-
-#define COMMAND_LINE_SIZE 256
-static char command_line[COMMAND_LINE_SIZE];
-char saved_command_line[COMMAND_LINE_SIZE];
-
-static void __init parse_mem_cmdline (char ** cmdline_p)
-{
- char c = ' ', *to = command_line, *from = saved_command_line;
- int len = 0;
-
- /* Save unparsed command line copy for /proc/cmdline */
- memcpy(saved_command_line, start_info.cmd_line, COMMAND_LINE_SIZE);
- saved_command_line[COMMAND_LINE_SIZE-1] = '\0';
-
- for (;;) {
- /*
- * "mem=nopentium" disables the 4MB page tables.
- * "mem=XXX[kKmM]" defines a memory region from HIGH_MEM
- * to <mem>, overriding the bios size.
- * "mem=XXX[KkmM]@XXX[KkmM]" defines a memory region from
- * <start> to <start>+<mem>, overriding the bios size.
- */
- if (c == ' ' && !memcmp(from, "mem=", 4)) {
- if (to != command_line)
- to--;
- if (!memcmp(from+4, "nopentium", 9)) {
- from += 9+4;
- } else if (!memcmp(from+4, "exactmap", 8)) {
- from += 8+4;
- } else {
- (void)memparse(from+4, &from);
- if (*from == '@')
- (void)memparse(from+1, &from);
- }
- }
-
- c = *(from++);
- if (!c)
- break;
- if (COMMAND_LINE_SIZE <= ++len)
- break;
- *(to++) = c;
- }
- *to = '\0';
- *cmdline_p = command_line;
-}
-
-void __init setup_arch(char **cmdline_p)
-{
- unsigned long start_pfn, max_pfn, max_low_pfn;
- unsigned long bootmap_size;
- unsigned long i;
-
- extern void hypervisor_callback(void);
- extern void failsafe_callback(void);
-
- extern unsigned long cpu0_pte_quicklist[];
- extern unsigned long cpu0_pgd_quicklist[];
-
- HYPERVISOR_set_callbacks(
- __KERNEL_CS, (unsigned long)hypervisor_callback,
- __KERNEL_CS, (unsigned long)failsafe_callback);
-
- boot_cpu_data.pgd_quick = cpu0_pgd_quicklist;
- boot_cpu_data.pte_quick = cpu0_pte_quicklist;
-
- ROOT_DEV = MKDEV(RAMDISK_MAJOR,0);
- memset(&drive_info, 0, sizeof(drive_info));
- memset(&screen_info, 0, sizeof(screen_info));
- // this is drawn from a dump from vgacon:startup in standard linux
- screen_info.orig_video_mode = 3;
- screen_info.orig_video_isVGA = 1;
- screen_info.orig_video_lines = 25;
- screen_info.orig_video_cols = 80;
- screen_info.orig_video_ega_bx = 3;
- screen_info.orig_video_points = 16;
-
- memset(&apm_info.bios, 0, sizeof(apm_info.bios));
- aux_device_present = 0;
-#ifdef CONFIG_BLK_DEV_RAM
- rd_image_start = 0;
- rd_prompt = 0;
- rd_doload = 0;
-#endif
-
- root_mountflags &= ~MS_RDONLY;
- init_mm.start_code = (unsigned long) &_text;
- init_mm.end_code = (unsigned long) &_etext;
- init_mm.end_data = (unsigned long) &_edata;
- init_mm.brk = (unsigned long) &_end;
-
- parse_mem_cmdline(cmdline_p);
-
-#define PFN_UP(x) (((x) + PAGE_SIZE-1) >> PAGE_SHIFT)
-#define PFN_DOWN(x) ((x) >> PAGE_SHIFT)
-#define PFN_PHYS(x) ((x) << PAGE_SHIFT)
-
-/*
- * 128MB for vmalloc and initrd
- */
-#define VMALLOC_RESERVE (unsigned long)(128 << 20)
-#define MAXMEM (unsigned long)(HYPERVISOR_VIRT_START-PAGE_OFFSET-VMALLOC_RESERVE)
-#define MAXMEM_PFN PFN_DOWN(MAXMEM)
-#define MAX_NONPAE_PFN (1 << 20)
-
- /*
- * partially used pages are not usable - thus
- * we are rounding upwards:
- */
-#ifdef CONFIG_BLK_DEV_INITRD
- if ( start_info.mod_start )
- start_pfn = PFN_UP(__pa(start_info.mod_start + start_info.mod_len));
- else
-#endif
- start_pfn = PFN_UP(__pa(&_end));
- max_pfn = start_info.nr_pages;
-
- /*
- * Determine low and high memory ranges:
- */
- max_low_pfn = max_pfn;
- if (max_low_pfn > MAXMEM_PFN) {
- max_low_pfn = MAXMEM_PFN;
-#ifndef CONFIG_HIGHMEM
- /* Maximum memory usable is what is directly addressable */
- printk(KERN_WARNING "Warning only %ldMB will be used.\n",
- MAXMEM>>20);
- if (max_pfn > MAX_NONPAE_PFN)
- printk(KERN_WARNING "Use a PAE enabled kernel.\n");
- else
- printk(KERN_WARNING "Use a HIGHMEM enabled kernel.\n");
-#else /* !CONFIG_HIGHMEM */
-#ifndef CONFIG_X86_PAE
- if (max_pfn > MAX_NONPAE_PFN) {
- max_pfn = MAX_NONPAE_PFN;
- printk(KERN_WARNING "Warning only 4GB will be used.\n");
- printk(KERN_WARNING "Use a PAE enabled kernel.\n");
- }
-#endif /* !CONFIG_X86_PAE */
-#endif /* !CONFIG_HIGHMEM */
- }
-
-#ifdef CONFIG_HIGHMEM
- highstart_pfn = highend_pfn = max_pfn;
- if (max_pfn > MAXMEM_PFN) {
- highstart_pfn = MAXMEM_PFN;
- printk(KERN_NOTICE "%ldMB HIGHMEM available.\n",
- pages_to_mb(highend_pfn - highstart_pfn));
- }
-#endif
-
- /*
- * Initialize the boot-time allocator, and free up all RAM.
- * Then reserve space for OS image, and the bootmem bitmap.
- */
- bootmap_size = init_bootmem(start_pfn, max_low_pfn);
- free_bootmem(0, PFN_PHYS(max_low_pfn));
- reserve_bootmem(0, PFN_PHYS(start_pfn) + bootmap_size + PAGE_SIZE-1);
-
- /* Now reserve space for the hypervisor-provided page tables. */
- {
- unsigned long *pgd = (unsigned long *)start_info.pt_base;
- unsigned long pte;
- int i;
- reserve_bootmem(__pa(pgd), PAGE_SIZE);
- for ( i = 0; i < (HYPERVISOR_VIRT_START>>22); i++ )
- {
- unsigned long pgde = *pgd++;
- if ( !(pgde & 1) ) continue;
- pte = machine_to_phys(pgde & PAGE_MASK);
- reserve_bootmem(pte, PAGE_SIZE);
- }
- }
- cur_pgd = init_mm.pgd = (pgd_t *)start_info.pt_base;
-
- /* Now initialise the physical->machine mapping table. */
- phys_to_machine_mapping = alloc_bootmem(max_pfn * sizeof(unsigned long));
- for ( i = 0; i < max_pfn; i++ )
- {
- unsigned long pgde, *ppte;
- unsigned long pfn = i + (PAGE_OFFSET >> PAGE_SHIFT);
- pgde = *((unsigned long *)start_info.pt_base + (pfn >> 10));
- ppte = (unsigned long *)machine_to_phys(pgde & PAGE_MASK) + (pfn&1023);
- phys_to_machine_mapping[i] =
- (*(unsigned long *)__va(ppte)) >> PAGE_SHIFT;
- }
-
-#ifdef CONFIG_BLK_DEV_INITRD
- if (start_info.mod_start) {
- if ((__pa(start_info.mod_start) + start_info.mod_len) <=
- (max_low_pfn << PAGE_SHIFT)) {
- initrd_start = start_info.mod_start;
- initrd_end = initrd_start + start_info.mod_len;
- initrd_below_start_ok = 1;
- }
- else {
- printk(KERN_ERR "initrd extends beyond end of memory "
- "(0x%08lx > 0x%08lx)\ndisabling initrd\n",
- __pa(start_info.mod_start) + start_info.mod_len,
- max_low_pfn << PAGE_SHIFT);
- initrd_start = 0;
- }
- }
-#endif
-
- paging_init();
-
- current->thread.hypercall_pl = 1;
- if ( start_info.flags & SIF_PRIVILEGED ) {
- current->thread.io_pl = 1;
- /* We are privileged guest os - should have IO privileges. */
- if( HYPERVISOR_set_priv_levels(1, 1) )
- panic("Unable to obtain IOPL, despite being SIF_PRIVILEGED");
- }
-
- if(start_info.flags & SIF_CONSOLE)
- {
- if( !(start_info.flags & SIF_PRIVILEGED) )
- panic("Xen granted us console access but not privileged status");
-
-#ifdef CONFIG_VT
-#if defined(CONFIG_VGA_CONSOLE)
- conswitchp = &vga_con;
-#elif defined(CONFIG_DUMMY_CONSOLE)
- conswitchp = &dummy_con;
-#endif
-#endif
- }
-}
-
-static int cachesize_override __initdata = -1;
-static int __init cachesize_setup(char *str)
-{
- get_option (&str, &cachesize_override);
- return 1;
-}
-__setup("cachesize=", cachesize_setup);
-
-
-static int __init get_model_name(struct cpuinfo_x86 *c)
-{
- unsigned int *v;
- char *p, *q;
-
- if (cpuid_eax(0x80000000) < 0x80000004)
- return 0;
-
- v = (unsigned int *) c->x86_model_id;
- cpuid(0x80000002, &v[0], &v[1], &v[2], &v[3]);
- cpuid(0x80000003, &v[4], &v[5], &v[6], &v[7]);
- cpuid(0x80000004, &v[8], &v[9], &v[10], &v[11]);
- c->x86_model_id[48] = 0;
-
- /* Intel chips right-justify this string for some dumb reason;
- undo that brain damage */
- p = q = &c->x86_model_id[0];
- while ( *p == ' ' )
- p++;
- if ( p != q ) {
- while ( *p )
- *q++ = *p++;
- while ( q <= &c->x86_model_id[48] )
- *q++ = '\0'; /* Zero-pad the rest */
- }
-
- return 1;
-}
-
-
-static void __init display_cacheinfo(struct cpuinfo_x86 *c)
-{
- unsigned int n, dummy, ecx, edx, l2size;
-
- n = cpuid_eax(0x80000000);
-
- if (n >= 0x80000005) {
- cpuid(0x80000005, &dummy, &dummy, &ecx, &edx);
- printk(KERN_INFO "CPU: L1 I Cache: %dK (%d bytes/line), D cache %dK (%d bytes/line)\n",
- edx>>24, edx&0xFF, ecx>>24, ecx&0xFF);
- c->x86_cache_size=(ecx>>24)+(edx>>24);
- }
-
- if (n < 0x80000006) /* Some chips just has a large L1. */
- return;
-
- ecx = cpuid_ecx(0x80000006);
- l2size = ecx >> 16;
-
- /* AMD errata T13 (order #21922) */
- if ((c->x86_vendor == X86_VENDOR_AMD) && (c->x86 == 6)) {
- if (c->x86_model == 3 && c->x86_mask == 0) /* Duron Rev A0 */
- l2size = 64;
- if (c->x86_model == 4 &&
- (c->x86_mask==0 || c->x86_mask==1)) /* Tbird rev A1/A2 */
- l2size = 256;
- }
-
- /* Intel PIII Tualatin. This comes in two flavours.
- * One has 256kb of cache, the other 512. We have no way
- * to determine which, so we use a boottime override
- * for the 512kb model, and assume 256 otherwise.
- */
- if ((c->x86_vendor == X86_VENDOR_INTEL) && (c->x86 == 6) &&
- (c->x86_model == 11) && (l2size == 0))
- l2size = 256;
-
- /* VIA C3 CPUs (670-68F) need further shifting. */
- if (c->x86_vendor == X86_VENDOR_CENTAUR && (c->x86 == 6) &&
- ((c->x86_model == 7) || (c->x86_model == 8))) {
- l2size = l2size >> 8;
- }
-
- /* Allow user to override all this if necessary. */
- if (cachesize_override != -1)
- l2size = cachesize_override;
-
- if ( l2size == 0 )
- return; /* Again, no L2 cache is possible */
-
- c->x86_cache_size = l2size;
-
- printk(KERN_INFO "CPU: L2 Cache: %dK (%d bytes/line)\n",
- l2size, ecx & 0xFF);
-}
-
-
-static int __init init_amd(struct cpuinfo_x86 *c)
-{
- int r;
-
- /* Bit 31 in normal CPUID used for nonstandard 3DNow ID;
- 3DNow is IDd by bit 31 in extended CPUID (1*32+31) anyway */
- clear_bit(0*32+31, &c->x86_capability);
-
- r = get_model_name(c);
-
- switch(c->x86)
- {
- case 6: /* An Athlon/Duron. We can trust the BIOS probably */
- break;
- default:
- panic("Unsupported AMD processor\n");
- }
-
- display_cacheinfo(c);
- return r;
-}
-
-
-static void __init init_intel(struct cpuinfo_x86 *c)
-{
- char *p = NULL;
- unsigned int l1i = 0, l1d = 0, l2 = 0, l3 = 0; /* Cache sizes */
-
- if (c->cpuid_level > 1) {
- /* supports eax=2 call */
- int i, j, n;
- int regs[4];
- unsigned char *dp = (unsigned char *)regs;
-
- /* Number of times to iterate */
- n = cpuid_eax(2) & 0xFF;
-
- for ( i = 0 ; i < n ; i++ ) {
- cpuid(2, ®s[0], ®s[1], ®s[2], ®s[3]);
-
- /* If bit 31 is set, this is an unknown format */
- for ( j = 0 ; j < 3 ; j++ ) {
- if ( regs[j] < 0 ) regs[j] = 0;
- }
-
- /* Byte 0 is level count, not a descriptor */
- for ( j = 1 ; j < 16 ; j++ ) {
- unsigned char des = dp[j];
- unsigned char dl, dh;
- unsigned int cs;
-
- dh = des >> 4;
- dl = des & 0x0F;
-
- /* Black magic... */
-
- switch ( dh )
- {
- case 0:
- switch ( dl ) {
- case 6:
- /* L1 I cache */
- l1i += 8;
- break;
- case 8:
- /* L1 I cache */
- l1i += 16;
- break;
- case 10:
- /* L1 D cache */
- l1d += 8;
- break;
- case 12:
- /* L1 D cache */
- l1d += 16;
- break;
- default:;
- /* TLB, or unknown */
- }
- break;
- case 2:
- if ( dl ) {
- /* L3 cache */
- cs = (dl-1) << 9;
- l3 += cs;
- }
- break;
- case 4:
- if ( c->x86 > 6 && dl ) {
- /* P4 family */
- /* L3 cache */
- cs = 128 << (dl-1);
- l3 += cs;
- break;
- }
- /* else same as 8 - fall through */
- case 8:
- if ( dl ) {
- /* L2 cache */
- cs = 128 << (dl-1);
- l2 += cs;
- }
- break;
- case 6:
- if (dl > 5) {
- /* L1 D cache */
- cs = 8<<(dl-6);
- l1d += cs;
- }
- break;
- case 7:
- if ( dl >= 8 )
- {
- /* L2 cache */
- cs = 64<<(dl-8);
- l2 += cs;
- } else {
- /* L0 I cache, count as L1 */
- cs = dl ? (16 << (dl-1)) : 12;
- l1i += cs;
- }
- break;
- default:
- /* TLB, or something else we don't know about */
- break;
- }
- }
- }
- if ( l1i || l1d )
- printk(KERN_INFO "CPU: L1 I cache: %dK, L1 D cache: %dK\n",
- l1i, l1d);
- if ( l2 )
- printk(KERN_INFO "CPU: L2 cache: %dK\n", l2);
- if ( l3 )
- printk(KERN_INFO "CPU: L3 cache: %dK\n", l3);
-
- /*
- * This assumes the L3 cache is shared; it typically lives in
- * the northbridge. The L1 caches are included by the L2
- * cache, and so should not be included for the purpose of
- * SMP switching weights.
- */
- c->x86_cache_size = l2 ? l2 : (l1i+l1d);
- }
-
- /* SEP CPUID bug: Pentium Pro reports SEP but doesn't have it */
- if ( c->x86 == 6 && c->x86_model < 3 && c->x86_mask < 3 )
- clear_bit(X86_FEATURE_SEP, &c->x86_capability);
-
- /* Names for the Pentium II/Celeron processors
- detectable only by also checking the cache size.
- Dixon is NOT a Celeron. */
- if (c->x86 == 6) {
- switch (c->x86_model) {
- case 5:
- if (l2 == 0)
- p = "Celeron (Covington)";
- if (l2 == 256)
- p = "Mobile Pentium II (Dixon)";
- break;
-
- case 6:
- if (l2 == 128)
- p = "Celeron (Mendocino)";
- break;
-
- case 8:
- if (l2 == 128)
- p = "Celeron (Coppermine)";
- break;
- }
- }
-
- if ( p )
- strcpy(c->x86_model_id, p);
-}
-
-void __init get_cpu_vendor(struct cpuinfo_x86 *c)
-{
- char *v = c->x86_vendor_id;
-
- if (!strcmp(v, "GenuineIntel"))
- c->x86_vendor = X86_VENDOR_INTEL;
- else if (!strcmp(v, "AuthenticAMD"))
- c->x86_vendor = X86_VENDOR_AMD;
- else
- c->x86_vendor = X86_VENDOR_UNKNOWN;
-}
-
-struct cpu_model_info {
- int vendor;
- int family;
- char *model_names[16];
-};
-
-/* Naming convention should be: <Name> [(<Codename>)] */
-/* This table only is used unless init_<vendor>() below doesn't set it; */
-/* in particular, if CPUID levels 0x80000002..4 are supported, this isn't used */
-static struct cpu_model_info cpu_models[] __initdata = {
- { X86_VENDOR_INTEL, 6,
- { "Pentium Pro A-step", "Pentium Pro", NULL, "Pentium II (Klamath)",
- NULL, "Pentium II (Deschutes)", "Mobile Pentium II",
- "Pentium III (Katmai)", "Pentium III (Coppermine)", NULL,
- "Pentium III (Cascades)", NULL, NULL, NULL, NULL }},
- { X86_VENDOR_AMD, 6, /* Is this this really necessary?? */
- { "Athlon", "Athlon",
- "Athlon", NULL, "Athlon", NULL,
- NULL, NULL, NULL,
- NULL, NULL, NULL, NULL, NULL, NULL, NULL }}
-};
-
-/* Look up CPU names by table lookup. */
-static char __init *table_lookup_model(struct cpuinfo_x86 *c)
-{
- struct cpu_model_info *info = cpu_models;
- int i;
-
- if ( c->x86_model >= 16 )
- return NULL; /* Range check */
-
- for ( i = 0 ; i < sizeof(cpu_models)/sizeof(struct cpu_model_info) ; i++ ) {
- if ( info->vendor == c->x86_vendor &&
- info->family == c->x86 ) {
- return info->model_names[c->x86_model];
- }
- info++;
- }
- return NULL; /* Not found */
-}
-
-
-
-/* Standard macro to see if a specific flag is changeable */
-static inline int flag_is_changeable_p(u32 flag)
-{
- u32 f1, f2;
-
- asm("pushfl\n\t"
- "pushfl\n\t"
- "popl %0\n\t"
- "movl %0,%1\n\t"
- "xorl %2,%0\n\t"
- "pushl %0\n\t"
- "popfl\n\t"
- "pushfl\n\t"
- "popl %0\n\t"
- "popfl\n\t"
- : "=&r" (f1), "=&r" (f2)
- : "ir" (flag));
-
- return ((f1^f2) & flag) != 0;
-}
-
-
-/* Probe for the CPUID instruction */
-static int __init have_cpuid_p(void)
-{
- return flag_is_changeable_p(X86_EFLAGS_ID);
-}
-
-
-
-/*
- * This does the hard work of actually picking apart the CPU stuff...
- */
-void __init identify_cpu(struct cpuinfo_x86 *c)
-{
- int junk, i;
- u32 xlvl, tfms;
-
- c->loops_per_jiffy = loops_per_jiffy;
- c->x86_cache_size = -1;
- c->x86_vendor = X86_VENDOR_UNKNOWN;
- c->cpuid_level = -1; /* CPUID not detected */
- c->x86_model = c->x86_mask = 0; /* So far unknown... */
- c->x86_vendor_id[0] = '\0'; /* Unset */
- c->x86_model_id[0] = '\0'; /* Unset */
- memset(&c->x86_capability, 0, sizeof c->x86_capability);
- c->hard_math = 1;
-
- if ( !have_cpuid_p() ) {
- panic("Processor must support CPUID\n");
- } else {
- /* CPU does have CPUID */
-
- /* Get vendor name */
- cpuid(0x00000000, &c->cpuid_level,
- (int *)&c->x86_vendor_id[0],
- (int *)&c->x86_vendor_id[8],
- (int *)&c->x86_vendor_id[4]);
-
- get_cpu_vendor(c);
- /* Initialize the standard set of capabilities */
- /* Note that the vendor-specific code below might override */
-
- /* Intel-defined flags: level 0x00000001 */
- if ( c->cpuid_level >= 0x00000001 ) {
- cpuid(0x00000001, &tfms, &junk, &junk,
- &c->x86_capability[0]);
- c->x86 = (tfms >> 8) & 15;
- c->x86_model = (tfms >> 4) & 15;
- c->x86_mask = tfms & 15;
- } else {
- /* Have CPUID level 0 only - unheard of */
- c->x86 = 4;
- }
-
- /* AMD-defined flags: level 0x80000001 */
- xlvl = cpuid_eax(0x80000000);
- if ( (xlvl & 0xffff0000) == 0x80000000 ) {
- if ( xlvl >= 0x80000001 )
- c->x86_capability[1] = cpuid_edx(0x80000001);
- if ( xlvl >= 0x80000004 )
- get_model_name(c); /* Default name */
- }
-
- /* Transmeta-defined flags: level 0x80860001 */
- xlvl = cpuid_eax(0x80860000);
- if ( (xlvl & 0xffff0000) == 0x80860000 ) {
- if ( xlvl >= 0x80860001 )
- c->x86_capability[2] = cpuid_edx(0x80860001);
- }
- }
-
- printk(KERN_DEBUG "CPU: Before vendor init, caps: %08x %08x %08x, vendor = %d\n",
- c->x86_capability[0],
- c->x86_capability[1],
- c->x86_capability[2],
- c->x86_vendor);
-
- /*
- * Vendor-specific initialization. In this section we
- * canonicalize the feature flags, meaning if there are
- * features a certain CPU supports which CPUID doesn't
- * tell us, CPUID claiming incorrect flags, or other bugs,
- * we handle them here.
- *
- * At the end of this section, c->x86_capability better
- * indicate the features this CPU genuinely supports!
- */
- switch ( c->x86_vendor ) {
- case X86_VENDOR_AMD:
- init_amd(c);
- break;
-
- case X86_VENDOR_INTEL:
- init_intel(c);
- break;
-
- default:
- panic("Unsupported CPU vendor\n");
- }
-
- printk(KERN_DEBUG "CPU: After vendor init, caps: %08x %08x %08x %08x\n",
- c->x86_capability[0],
- c->x86_capability[1],
- c->x86_capability[2],
- c->x86_capability[3]);
-
-
- /* If the model name is still unset, do table lookup. */
- if ( !c->x86_model_id[0] ) {
- char *p;
- p = table_lookup_model(c);
- if ( p )
- strcpy(c->x86_model_id, p);
- else
- /* Last resort... */
- sprintf(c->x86_model_id, "%02x/%02x",
- c->x86_vendor, c->x86_model);
- }
-
- /* Now the feature flags better reflect actual CPU features! */
-
- printk(KERN_DEBUG "CPU: After generic, caps: %08x %08x %08x %08x\n",
- c->x86_capability[0],
- c->x86_capability[1],
- c->x86_capability[2],
- c->x86_capability[3]);
-
- /*
- * On SMP, boot_cpu_data holds the common feature set between
- * all CPUs; so make sure that we indicate which features are
- * common between the CPUs. The first time this routine gets
- * executed, c == &boot_cpu_data.
- */
- if ( c != &boot_cpu_data ) {
- /* AND the already accumulated flags with these */
- for ( i = 0 ; i < NCAPINTS ; i++ )
- boot_cpu_data.x86_capability[i] &= c->x86_capability[i];
- }
-
- printk(KERN_DEBUG "CPU: Common caps: %08x %08x %08x %08x\n",
- boot_cpu_data.x86_capability[0],
- boot_cpu_data.x86_capability[1],
- boot_cpu_data.x86_capability[2],
- boot_cpu_data.x86_capability[3]);
-}
-
-
-/* These need to match <asm/processor.h> */
-static char *cpu_vendor_names[] __initdata = {
- "Intel", "Cyrix", "AMD", "UMC", "NexGen", "Centaur", "Rise", "Transmeta" };
-
-
-void __init print_cpu_info(struct cpuinfo_x86 *c)
-{
- char *vendor = NULL;
-
- if (c->x86_vendor < sizeof(cpu_vendor_names)/sizeof(char *))
- vendor = cpu_vendor_names[c->x86_vendor];
- else if (c->cpuid_level >= 0)
- vendor = c->x86_vendor_id;
-
- if (vendor && strncmp(c->x86_model_id, vendor, strlen(vendor)))
- printk("%s ", vendor);
-
- if (!c->x86_model_id[0])
- printk("%d86", c->x86);
- else
- printk("%s", c->x86_model_id);
-
- if (c->x86_mask || c->cpuid_level >= 0)
- printk(" stepping %02x\n", c->x86_mask);
- else
- printk("\n");
-}
-
-/*
- * Get CPU information for use by the procfs.
- */
-static int show_cpuinfo(struct seq_file *m, void *v)
-{
- /*
- * These flag bits must match the definitions in <asm/cpufeature.h>.
- * NULL means this bit is undefined or reserved; either way it doesn't
- * have meaning as far as Linux is concerned. Note that it's important
- * to realize there is a difference between this table and CPUID -- if
- * applications want to get the raw CPUID data, they should access
- * /dev/cpu/<cpu_nr>/cpuid instead.
- */
- static char *x86_cap_flags[] = {
- /* Intel-defined */
- "fpu", "vme", "de", "pse", "tsc", "msr", "pae", "mce",
- "cx8", "apic", NULL, "sep", "mtrr", "pge", "mca", "cmov",
- "pat", "pse36", "pn", "clflush", NULL, "dts", "acpi", "mmx",
- "fxsr", "sse", "sse2", "ss", NULL, "tm", "ia64", NULL,
-
- /* AMD-defined */
- NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, "syscall", NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL, NULL, NULL, "mmxext", NULL,
- NULL, NULL, NULL, NULL, NULL, "lm", "3dnowext", "3dnow",
-
- /* Transmeta-defined */
- "recovery", "longrun", NULL, "lrti", NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
-
- /* Other (Linux-defined) */
- "cxmmx", "k6_mtrr", "cyrix_arr", "centaur_mcr", NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- };
- struct cpuinfo_x86 *c = v;
- int i, n = c - cpu_data;
- int fpu_exception;
-
-#ifdef CONFIG_SMP
- if (!(cpu_online_map & (1<<n)))
- return 0;
-#endif
- seq_printf(m, "processor\t: %d\n"
- "vendor_id\t: %s\n"
- "cpu family\t: %d\n"
- "model\t\t: %d\n"
- "model name\t: %s\n",
- n,
- c->x86_vendor_id[0] ? c->x86_vendor_id : "unknown",
- c->x86,
- c->x86_model,
- c->x86_model_id[0] ? c->x86_model_id : "unknown");
-
- if (c->x86_mask || c->cpuid_level >= 0)
- seq_printf(m, "stepping\t: %d\n", c->x86_mask);
- else
- seq_printf(m, "stepping\t: unknown\n");
-
- if ( test_bit(X86_FEATURE_TSC, &c->x86_capability) ) {
- seq_printf(m, "cpu MHz\t\t: %lu.%03lu\n",
- cpu_khz / 1000, (cpu_khz % 1000));
- }
-
- /* Cache size */
- if (c->x86_cache_size >= 0)
- seq_printf(m, "cache size\t: %d KB\n", c->x86_cache_size);
-
- /* We use exception 16 if we have hardware math and we've either seen it or the CPU claims it is internal */
- fpu_exception = c->hard_math && (ignore_irq13 || cpu_has_fpu);
- seq_printf(m, "fdiv_bug\t: %s\n"
- "hlt_bug\t\t: %s\n"
- "f00f_bug\t: %s\n"
- "coma_bug\t: %s\n"
- "fpu\t\t: %s\n"
- "fpu_exception\t: %s\n"
- "cpuid level\t: %d\n"
- "wp\t\t: %s\n"
- "flags\t\t:",
- c->fdiv_bug ? "yes" : "no",
- c->hlt_works_ok ? "no" : "yes",
- c->f00f_bug ? "yes" : "no",
- c->coma_bug ? "yes" : "no",
- c->hard_math ? "yes" : "no",
- fpu_exception ? "yes" : "no",
- c->cpuid_level,
- c->wp_works_ok ? "yes" : "no");
-
- for ( i = 0 ; i < 32*NCAPINTS ; i++ )
- if ( test_bit(i, &c->x86_capability) &&
- x86_cap_flags[i] != NULL )
- seq_printf(m, " %s", x86_cap_flags[i]);
-
- seq_printf(m, "\nbogomips\t: %lu.%02lu\n\n",
- c->loops_per_jiffy/(500000/HZ),
- (c->loops_per_jiffy/(5000/HZ)) % 100);
- return 0;
-}
-
-static void *c_start(struct seq_file *m, loff_t *pos)
-{
- return *pos < NR_CPUS ? cpu_data + *pos : NULL;
-}
-static void *c_next(struct seq_file *m, void *v, loff_t *pos)
-{
- ++*pos;
- return c_start(m, pos);
-}
-static void c_stop(struct seq_file *m, void *v)
-{
-}
-struct seq_operations cpuinfo_op = {
- start: c_start,
- next: c_next,
- stop: c_stop,
- show: show_cpuinfo,
-};
-
-unsigned long cpu_initialized __initdata = 0;
-
-/*
- * cpu_init() initializes state that is per-CPU. Some data is already
- * initialized (naturally) in the bootstrap process, such as the GDT
- * and IDT. We reload them nevertheless, this function acts as a
- * 'CPU state barrier', nothing should get across.
- */
-void __init cpu_init (void)
-{
- int nr = smp_processor_id();
-
- if (test_and_set_bit(nr, &cpu_initialized)) {
- printk(KERN_WARNING "CPU#%d already initialized!\n", nr);
- for (;;) __sti();
- }
- printk(KERN_INFO "Initializing CPU#%d\n", nr);
-
- /*
- * set up and load the per-CPU TSS and LDT
- */
- atomic_inc(&init_mm.mm_count);
- current->active_mm = &init_mm;
- if(current->mm)
- BUG();
- enter_lazy_tlb(&init_mm, current, nr);
-
- HYPERVISOR_stack_switch(__KERNEL_DS, current->thread.esp0);
-
- load_LDT(&init_mm);
- flush_page_update_queue();
-
- /* Force FPU initialization. */
- current->flags &= ~PF_USEDFPU;
- current->used_math = 0;
- stts();
-}
-
-
-/******************************************************************************
- * Time-to-die callback handling.
- */
-
-static void time_to_die(int irq, void *unused, struct pt_regs *regs)
-{
- extern void ctrl_alt_del(void);
- ctrl_alt_del();
-}
-
-static int __init setup_death_event(void)
-{
- (void)request_irq(_EVENT_DIE, time_to_die, 0, "die", NULL);
- return 0;
-}
-
-__initcall(setup_death_event);
+++ /dev/null
-/*
- * linux/arch/i386/kernel/signal.c
- *
- * Copyright (C) 1991, 1992 Linus Torvalds
- *
- * 1997-11-28 Modified for POSIX.1b signals by Richard Henderson
- * 2000-06-20 Pentium III FXSR, SSE support by Gareth Hughes
- */
-
-#include <linux/sched.h>
-#include <linux/mm.h>
-#include <linux/smp.h>
-#include <linux/smp_lock.h>
-#include <linux/kernel.h>
-#include <linux/signal.h>
-#include <linux/errno.h>
-#include <linux/wait.h>
-#include <linux/ptrace.h>
-#include <linux/unistd.h>
-#include <linux/stddef.h>
-#include <linux/tty.h>
-#include <linux/personality.h>
-#include <asm/ucontext.h>
-#include <asm/uaccess.h>
-#include <asm/i387.h>
-
-#define DEBUG_SIG 0
-
-#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
-
-int FASTCALL(do_signal(struct pt_regs *regs, sigset_t *oldset));
-
-int copy_siginfo_to_user(siginfo_t *to, siginfo_t *from)
-{
- if (!access_ok (VERIFY_WRITE, to, sizeof(siginfo_t)))
- return -EFAULT;
- if (from->si_code < 0)
- return __copy_to_user(to, from, sizeof(siginfo_t));
- else {
- int err;
-
- /* If you change siginfo_t structure, please be sure
- this code is fixed accordingly.
- It should never copy any pad contained in the structure
- to avoid security leaks, but must copy the generic
- 3 ints plus the relevant union member. */
- err = __put_user(from->si_signo, &to->si_signo);
- err |= __put_user(from->si_errno, &to->si_errno);
- err |= __put_user((short)from->si_code, &to->si_code);
- /* First 32bits of unions are always present. */
- err |= __put_user(from->si_pid, &to->si_pid);
- switch (from->si_code >> 16) {
- case __SI_FAULT >> 16:
- break;
- case __SI_CHLD >> 16:
- err |= __put_user(from->si_utime, &to->si_utime);
- err |= __put_user(from->si_stime, &to->si_stime);
- err |= __put_user(from->si_status, &to->si_status);
- default:
- err |= __put_user(from->si_uid, &to->si_uid);
- break;
- /* case __SI_RT: This is not generated by the kernel as of now. */
- }
- return err;
- }
-}
-
-/*
- * Atomically swap in the new signal mask, and wait for a signal.
- */
-asmlinkage int
-sys_sigsuspend(int history0, int history1, old_sigset_t mask)
-{
- struct pt_regs * regs = (struct pt_regs *) &history0;
- sigset_t saveset;
-
- mask &= _BLOCKABLE;
- spin_lock_irq(¤t->sigmask_lock);
- saveset = current->blocked;
- siginitset(¤t->blocked, mask);
- recalc_sigpending(current);
- spin_unlock_irq(¤t->sigmask_lock);
-
- regs->eax = -EINTR;
- while (1) {
- current->state = TASK_INTERRUPTIBLE;
- schedule();
- if (do_signal(regs, &saveset))
- return -EINTR;
- }
-}
-
-asmlinkage int
-sys_rt_sigsuspend(sigset_t *unewset, size_t sigsetsize)
-{
- struct pt_regs * regs = (struct pt_regs *) &unewset;
- sigset_t saveset, newset;
-
- /* XXX: Don't preclude handling different sized sigset_t's. */
- if (sigsetsize != sizeof(sigset_t))
- return -EINVAL;
-
- if (copy_from_user(&newset, unewset, sizeof(newset)))
- return -EFAULT;
- sigdelsetmask(&newset, ~_BLOCKABLE);
-
- spin_lock_irq(¤t->sigmask_lock);
- saveset = current->blocked;
- current->blocked = newset;
- recalc_sigpending(current);
- spin_unlock_irq(¤t->sigmask_lock);
-
- regs->eax = -EINTR;
- while (1) {
- current->state = TASK_INTERRUPTIBLE;
- schedule();
- if (do_signal(regs, &saveset))
- return -EINTR;
- }
-}
-
-asmlinkage int
-sys_sigaction(int sig, const struct old_sigaction *act,
- struct old_sigaction *oact)
-{
- struct k_sigaction new_ka, old_ka;
- int ret;
-
- if (act) {
- old_sigset_t mask;
- if (verify_area(VERIFY_READ, act, sizeof(*act)) ||
- __get_user(new_ka.sa.sa_handler, &act->sa_handler) ||
- __get_user(new_ka.sa.sa_restorer, &act->sa_restorer))
- return -EFAULT;
- __get_user(new_ka.sa.sa_flags, &act->sa_flags);
- __get_user(mask, &act->sa_mask);
- siginitset(&new_ka.sa.sa_mask, mask);
- }
-
- ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
-
- if (!ret && oact) {
- if (verify_area(VERIFY_WRITE, oact, sizeof(*oact)) ||
- __put_user(old_ka.sa.sa_handler, &oact->sa_handler) ||
- __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer))
- return -EFAULT;
- __put_user(old_ka.sa.sa_flags, &oact->sa_flags);
- __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask);
- }
-
- return ret;
-}
-
-asmlinkage int
-sys_sigaltstack(const stack_t *uss, stack_t *uoss)
-{
- struct pt_regs *regs = (struct pt_regs *) &uss;
- return do_sigaltstack(uss, uoss, regs->esp);
-}
-
-
-/*
- * Do a signal return; undo the signal stack.
- */
-
-struct sigframe
-{
- char *pretcode;
- int sig;
- struct sigcontext sc;
- struct _fpstate fpstate;
- unsigned long extramask[_NSIG_WORDS-1];
- char retcode[8];
-};
-
-struct rt_sigframe
-{
- char *pretcode;
- int sig;
- struct siginfo *pinfo;
- void *puc;
- struct siginfo info;
- struct ucontext uc;
- struct _fpstate fpstate;
- char retcode[8];
-};
-
-static int
-restore_sigcontext(struct pt_regs *regs, struct sigcontext *sc, int *peax)
-{
- unsigned int err = 0;
-
-#define COPY(x) err |= __get_user(regs->x, &sc->x)
-
-#define COPY_SEG(seg) \
- { unsigned short tmp; \
- err |= __get_user(tmp, &sc->seg); \
- regs->x##seg = tmp; }
-
-#define COPY_SEG_STRICT(seg) \
- { unsigned short tmp; \
- err |= __get_user(tmp, &sc->seg); \
- regs->x##seg = tmp|3; }
-
-#define GET_SEG(seg) \
- { unsigned short tmp; \
- err |= __get_user(tmp, &sc->seg); \
- loadsegment(seg,tmp); }
-
- GET_SEG(gs);
- GET_SEG(fs);
- COPY_SEG(es);
- COPY_SEG(ds);
- COPY(edi);
- COPY(esi);
- COPY(ebp);
- COPY(esp);
- COPY(ebx);
- COPY(edx);
- COPY(ecx);
- COPY(eip);
- COPY_SEG_STRICT(cs);
- COPY_SEG_STRICT(ss);
-
- {
- unsigned int tmpflags;
- err |= __get_user(tmpflags, &sc->eflags);
- regs->eflags = (regs->eflags & ~0x40DD5) | (tmpflags & 0x40DD5);
- regs->orig_eax = -1; /* disable syscall checks */
- }
-
- {
- struct _fpstate * buf;
- err |= __get_user(buf, &sc->fpstate);
- if (buf) {
- if (verify_area(VERIFY_READ, buf, sizeof(*buf)))
- goto badframe;
- err |= restore_i387(buf);
- }
- }
-
- err |= __get_user(*peax, &sc->eax);
- return err;
-
-badframe:
- return 1;
-}
-
-asmlinkage int sys_sigreturn(unsigned long __unused)
-{
- struct pt_regs *regs = (struct pt_regs *) &__unused;
- struct sigframe *frame = (struct sigframe *)(regs->esp - 8);
- sigset_t set;
- int eax;
-
- if (verify_area(VERIFY_READ, frame, sizeof(*frame)))
- goto badframe;
- if (__get_user(set.sig[0], &frame->sc.oldmask)
- || (_NSIG_WORDS > 1
- && __copy_from_user(&set.sig[1], &frame->extramask,
- sizeof(frame->extramask))))
- goto badframe;
-
- sigdelsetmask(&set, ~_BLOCKABLE);
- spin_lock_irq(¤t->sigmask_lock);
- current->blocked = set;
- recalc_sigpending(current);
- spin_unlock_irq(¤t->sigmask_lock);
-
- if (restore_sigcontext(regs, &frame->sc, &eax))
- goto badframe;
- return eax;
-
-badframe:
- force_sig(SIGSEGV, current);
- return 0;
-}
-
-asmlinkage int sys_rt_sigreturn(unsigned long __unused)
-{
- struct pt_regs *regs = (struct pt_regs *) &__unused;
- struct rt_sigframe *frame = (struct rt_sigframe *)(regs->esp - 4);
- sigset_t set;
- stack_t st;
- int eax;
-
- if (verify_area(VERIFY_READ, frame, sizeof(*frame)))
- goto badframe;
- if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set)))
- goto badframe;
-
- sigdelsetmask(&set, ~_BLOCKABLE);
- spin_lock_irq(¤t->sigmask_lock);
- current->blocked = set;
- recalc_sigpending(current);
- spin_unlock_irq(¤t->sigmask_lock);
-
- if (restore_sigcontext(regs, &frame->uc.uc_mcontext, &eax))
- goto badframe;
-
- if (__copy_from_user(&st, &frame->uc.uc_stack, sizeof(st)))
- goto badframe;
- /* It is more difficult to avoid calling this function than to
- call it and ignore errors. */
- do_sigaltstack(&st, NULL, regs->esp);
-
- return eax;
-
-badframe:
- force_sig(SIGSEGV, current);
- return 0;
-}
-
-/*
- * Set up a signal frame.
- */
-
-static int
-setup_sigcontext(struct sigcontext *sc, struct _fpstate *fpstate,
- struct pt_regs *regs, unsigned long mask)
-{
- int tmp, err = 0;
-
- tmp = 0;
- __asm__("movl %%gs,%0" : "=r"(tmp): "0"(tmp));
- err |= __put_user(tmp, (unsigned int *)&sc->gs);
- __asm__("movl %%fs,%0" : "=r"(tmp): "0"(tmp));
- err |= __put_user(tmp, (unsigned int *)&sc->fs);
-
- err |= __put_user(regs->xes, (unsigned int *)&sc->es);
- err |= __put_user(regs->xds, (unsigned int *)&sc->ds);
- err |= __put_user(regs->edi, &sc->edi);
- err |= __put_user(regs->esi, &sc->esi);
- err |= __put_user(regs->ebp, &sc->ebp);
- err |= __put_user(regs->esp, &sc->esp);
- err |= __put_user(regs->ebx, &sc->ebx);
- err |= __put_user(regs->edx, &sc->edx);
- err |= __put_user(regs->ecx, &sc->ecx);
- err |= __put_user(regs->eax, &sc->eax);
- err |= __put_user(current->thread.trap_no, &sc->trapno);
- err |= __put_user(current->thread.error_code, &sc->err);
- err |= __put_user(regs->eip, &sc->eip);
- err |= __put_user(regs->xcs, (unsigned int *)&sc->cs);
- err |= __put_user(regs->eflags, &sc->eflags);
- err |= __put_user(regs->esp, &sc->esp_at_signal);
- err |= __put_user(regs->xss, (unsigned int *)&sc->ss);
-
- tmp = save_i387(fpstate);
- if (tmp < 0)
- err = 1;
- else
- err |= __put_user(tmp ? fpstate : NULL, &sc->fpstate);
-
- /* non-iBCS2 extensions.. */
- err |= __put_user(mask, &sc->oldmask);
- err |= __put_user(current->thread.cr2, &sc->cr2);
-
- return err;
-}
-
-/*
- * Determine which stack to use..
- */
-static inline void *
-get_sigframe(struct k_sigaction *ka, struct pt_regs * regs, size_t frame_size)
-{
- unsigned long esp;
-
- /* Default to using normal stack */
- esp = regs->esp;
-
- /* This is the X/Open sanctioned signal stack switching. */
- if (ka->sa.sa_flags & SA_ONSTACK) {
- if (sas_ss_flags(esp) == 0)
- esp = current->sas_ss_sp + current->sas_ss_size;
- }
-
- /* This is the legacy signal stack switching. */
- else if ((regs->xss & 0xffff) != __USER_DS &&
- !(ka->sa.sa_flags & SA_RESTORER) &&
- ka->sa.sa_restorer) {
- esp = (unsigned long) ka->sa.sa_restorer;
- }
-
- return (void *)((esp - frame_size) & -8ul);
-}
-
-static void setup_frame(int sig, struct k_sigaction *ka,
- sigset_t *set, struct pt_regs * regs)
-{
- struct sigframe *frame;
- int err = 0;
-
- frame = get_sigframe(ka, regs, sizeof(*frame));
-
- if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
- goto give_sigsegv;
-
- err |= __put_user((current->exec_domain
- && current->exec_domain->signal_invmap
- && sig < 32
- ? current->exec_domain->signal_invmap[sig]
- : sig),
- &frame->sig);
- if (err)
- goto give_sigsegv;
-
- err |= setup_sigcontext(&frame->sc, &frame->fpstate, regs, set->sig[0]);
- if (err)
- goto give_sigsegv;
-
- if (_NSIG_WORDS > 1) {
- err |= __copy_to_user(frame->extramask, &set->sig[1],
- sizeof(frame->extramask));
- }
- if (err)
- goto give_sigsegv;
-
- /* Set up to return from userspace. If provided, use a stub
- already in userspace. */
- if (ka->sa.sa_flags & SA_RESTORER) {
- err |= __put_user(ka->sa.sa_restorer, &frame->pretcode);
- } else {
- err |= __put_user(frame->retcode, &frame->pretcode);
- /* This is popl %eax ; movl $,%eax ; int $0x80 */
- err |= __put_user(0xb858, (short *)(frame->retcode+0));
- err |= __put_user(__NR_sigreturn, (int *)(frame->retcode+2));
- err |= __put_user(0x80cd, (short *)(frame->retcode+6));
- }
-
- if (err)
- goto give_sigsegv;
-
- /* Set up registers for signal handler */
- regs->esp = (unsigned long) frame;
- regs->eip = (unsigned long) ka->sa.sa_handler;
-
- set_fs(USER_DS);
- regs->xds = __USER_DS;
- regs->xes = __USER_DS;
- regs->xss = __USER_DS;
- regs->xcs = __USER_CS;
- regs->eflags &= ~TF_MASK;
-
-#if DEBUG_SIG
- printk("SIG deliver (%s:%d): sp=%p pc=%p ra=%p\n",
- current->comm, current->pid, frame, regs->eip, frame->pretcode);
-#endif
-
- return;
-
-give_sigsegv:
- if (sig == SIGSEGV)
- ka->sa.sa_handler = SIG_DFL;
- force_sig(SIGSEGV, current);
-}
-
-static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
- sigset_t *set, struct pt_regs * regs)
-{
- struct rt_sigframe *frame;
- int err = 0;
-
- frame = get_sigframe(ka, regs, sizeof(*frame));
-
- if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
- goto give_sigsegv;
-
- err |= __put_user((current->exec_domain
- && current->exec_domain->signal_invmap
- && sig < 32
- ? current->exec_domain->signal_invmap[sig]
- : sig),
- &frame->sig);
- err |= __put_user(&frame->info, &frame->pinfo);
- err |= __put_user(&frame->uc, &frame->puc);
- err |= copy_siginfo_to_user(&frame->info, info);
- if (err)
- goto give_sigsegv;
-
- /* Create the ucontext. */
- err |= __put_user(0, &frame->uc.uc_flags);
- err |= __put_user(0, &frame->uc.uc_link);
- err |= __put_user(current->sas_ss_sp, &frame->uc.uc_stack.ss_sp);
- err |= __put_user(sas_ss_flags(regs->esp),
- &frame->uc.uc_stack.ss_flags);
- err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size);
- err |= setup_sigcontext(&frame->uc.uc_mcontext, &frame->fpstate,
- regs, set->sig[0]);
- err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
- if (err)
- goto give_sigsegv;
-
- /* Set up to return from userspace. If provided, use a stub
- already in userspace. */
- if (ka->sa.sa_flags & SA_RESTORER) {
- err |= __put_user(ka->sa.sa_restorer, &frame->pretcode);
- } else {
- err |= __put_user(frame->retcode, &frame->pretcode);
- /* This is movl $,%eax ; int $0x80 */
- err |= __put_user(0xb8, (char *)(frame->retcode+0));
- err |= __put_user(__NR_rt_sigreturn, (int *)(frame->retcode+1));
- err |= __put_user(0x80cd, (short *)(frame->retcode+5));
- }
-
- if (err)
- goto give_sigsegv;
-
- /* Set up registers for signal handler */
- regs->esp = (unsigned long) frame;
- regs->eip = (unsigned long) ka->sa.sa_handler;
-
- set_fs(USER_DS);
- regs->xds = __USER_DS;
- regs->xes = __USER_DS;
- regs->xss = __USER_DS;
- regs->xcs = __USER_CS;
- regs->eflags &= ~TF_MASK;
-
-#if DEBUG_SIG
- printk("SIG deliver (%s:%d): sp=%p pc=%p ra=%p\n",
- current->comm, current->pid, frame, regs->eip, frame->pretcode);
-#endif
-
- return;
-
-give_sigsegv:
- if (sig == SIGSEGV)
- ka->sa.sa_handler = SIG_DFL;
- force_sig(SIGSEGV, current);
-}
-
-/*
- * OK, we're invoking a handler
- */
-
-static void
-handle_signal(unsigned long sig, struct k_sigaction *ka,
- siginfo_t *info, sigset_t *oldset, struct pt_regs * regs)
-{
- /* Are we from a system call? */
- if (regs->orig_eax >= 0) {
- /* If so, check system call restarting.. */
- switch (regs->eax) {
- case -ERESTARTNOHAND:
- regs->eax = -EINTR;
- break;
-
- case -ERESTARTSYS:
- if (!(ka->sa.sa_flags & SA_RESTART)) {
- regs->eax = -EINTR;
- break;
- }
- /* fallthrough */
- case -ERESTARTNOINTR:
- regs->eax = regs->orig_eax;
- regs->eip -= 2;
- }
- }
-
- /* Set up the stack frame */
- if (ka->sa.sa_flags & SA_SIGINFO)
- setup_rt_frame(sig, ka, info, oldset, regs);
- else
- setup_frame(sig, ka, oldset, regs);
-
- if (ka->sa.sa_flags & SA_ONESHOT)
- ka->sa.sa_handler = SIG_DFL;
-
- if (!(ka->sa.sa_flags & SA_NODEFER)) {
- spin_lock_irq(¤t->sigmask_lock);
- sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask);
- sigaddset(¤t->blocked,sig);
- recalc_sigpending(current);
- spin_unlock_irq(¤t->sigmask_lock);
- }
-}
-
-/*
- * Note that 'init' is a special process: it doesn't get signals it doesn't
- * want to handle. Thus you cannot kill init even with a SIGKILL even by
- * mistake.
- */
-int do_signal(struct pt_regs *regs, sigset_t *oldset)
-{
- siginfo_t info;
- struct k_sigaction *ka;
-
- /*
- * We want the common case to go fast, which
- * is why we may in certain cases get here from
- * kernel mode. Just return without doing anything
- * if so.
- */
- if ((regs->xcs & 2) != 2)
- return 1;
-
- if (!oldset)
- oldset = ¤t->blocked;
-
- for (;;) {
- unsigned long signr;
-
- spin_lock_irq(¤t->sigmask_lock);
- signr = dequeue_signal(¤t->blocked, &info);
- spin_unlock_irq(¤t->sigmask_lock);
-
- if (!signr)
- break;
-
- if ((current->ptrace & PT_PTRACED) && signr != SIGKILL) {
- /* Let the debugger run. */
- current->exit_code = signr;
- current->state = TASK_STOPPED;
- notify_parent(current, SIGCHLD);
- schedule();
-
- /* We're back. Did the debugger cancel the sig? */
- if (!(signr = current->exit_code))
- continue;
- current->exit_code = 0;
-
- /* The debugger continued. Ignore SIGSTOP. */
- if (signr == SIGSTOP)
- continue;
-
- /* Update the siginfo structure. Is this good? */
- if (signr != info.si_signo) {
- info.si_signo = signr;
- info.si_errno = 0;
- info.si_code = SI_USER;
- info.si_pid = current->p_pptr->pid;
- info.si_uid = current->p_pptr->uid;
- }
-
- /* If the (new) signal is now blocked, requeue it. */
- if (sigismember(¤t->blocked, signr)) {
- send_sig_info(signr, &info, current);
- continue;
- }
- }
-
- ka = ¤t->sig->action[signr-1];
- if (ka->sa.sa_handler == SIG_IGN) {
- if (signr != SIGCHLD)
- continue;
- /* Check for SIGCHLD: it's special. */
- while (sys_wait4(-1, NULL, WNOHANG, NULL) > 0)
- /* nothing */;
- continue;
- }
-
- if (ka->sa.sa_handler == SIG_DFL) {
- int exit_code = signr;
-
- /* Init gets no signals it doesn't want. */
- if (current->pid == 1)
- continue;
-
- switch (signr) {
- case SIGCONT: case SIGCHLD: case SIGWINCH: case SIGURG:
- continue;
-
- case SIGTSTP: case SIGTTIN: case SIGTTOU:
- if (is_orphaned_pgrp(current->pgrp))
- continue;
- /* FALLTHRU */
-
- case SIGSTOP: {
- struct signal_struct *sig;
- current->state = TASK_STOPPED;
- current->exit_code = signr;
- sig = current->p_pptr->sig;
- if (sig && !(sig->action[SIGCHLD-1].sa.sa_flags & SA_NOCLDSTOP))
- notify_parent(current, SIGCHLD);
- schedule();
- continue;
- }
-
- case SIGQUIT: case SIGILL: case SIGTRAP:
- case SIGABRT: case SIGFPE: case SIGSEGV:
- case SIGBUS: case SIGSYS: case SIGXCPU: case SIGXFSZ:
- if (do_coredump(signr, regs))
- exit_code |= 0x80;
- /* FALLTHRU */
-
- default:
- sig_exit(signr, exit_code, &info);
- /* NOTREACHED */
- }
- }
-
- /* Reenable any watchpoints before delivering the
- * signal to user space. The processor register will
- * have been cleared if the watchpoint triggered
- * inside the kernel.
- */
- if ( current->thread.debugreg[7] != 0 )
- HYPERVISOR_set_debugreg(7, current->thread.debugreg[7]);
-
- /* Whee! Actually deliver the signal. */
- handle_signal(signr, ka, &info, oldset, regs);
- return 1;
- }
-
- /* Did we come from a system call? */
- if (regs->orig_eax >= 0) {
- /* Restart the system call - no handlers present */
- if (regs->eax == -ERESTARTNOHAND ||
- regs->eax == -ERESTARTSYS ||
- regs->eax == -ERESTARTNOINTR) {
- regs->eax = regs->orig_eax;
- regs->eip -= 2;
- }
- }
- return 0;
-}
+++ /dev/null
-/* -*- Mode:C; c-basic-offset:4; tab-width:4 -*-
- ****************************************************************************
- * (C) 2002 - Rolf Neugebauer - Intel Research Cambridge
- ****************************************************************************
- *
- * File: arch.xeno/time.c
- * Author: Rolf Neugebauer
- * Changes:
- *
- * Date: Nov 2002
- *
- * Environment: XenoLinux
- * Description: Interface with Hypervisor to get correct notion of time
- * Currently supports Systemtime and WallClock time.
- *
- * (This has hardly any resemblence with the Linux code but left the
- * copyright notice anyway. Ignore the comments in the copyright notice.)
- ****************************************************************************
- * $Id: c-insert.c,v 1.7 2002/11/08 16:04:34 rn Exp $
- ****************************************************************************
- */
-
-/*
- * linux/arch/i386/kernel/time.c
- *
- * Copyright (C) 1991, 1992, 1995 Linus Torvalds
- *
- * This file contains the PC-specific time handling details:
- * reading the RTC at bootup, etc..
- * 1994-07-02 Alan Modra
- * fixed set_rtc_mmss, fixed time.year for >= 2000, new mktime
- * 1995-03-26 Markus Kuhn
- * fixed 500 ms bug at call to set_rtc_mmss, fixed DS12887
- * precision CMOS clock update
- * 1996-05-03 Ingo Molnar
- * fixed time warps in do_[slow|fast]_gettimeoffset()
- * 1997-09-10 Updated NTP code according to technical memorandum Jan '96
- * "A Kernel Model for Precision Timekeeping" by Dave Mills
- * 1998-09-05 (Various)
- * More robust do_fast_gettimeoffset() algorithm implemented
- * (works with APM, Cyrix 6x86MX and Centaur C6),
- * monotonic gettimeofday() with fast_get_timeoffset(),
- * drift-proof precision TSC calibration on boot
- * (C. Scott Ananian <cananian@alumni.princeton.edu>, Andrew D.
- * Balsa <andrebalsa@altern.org>, Philip Gladstone <philip@raptor.com>;
- * ported from 2.0.35 Jumbo-9 by Michael Krause <m.krause@tu-harburg.de>).
- * 1998-12-16 Andrea Arcangeli
- * Fixed Jumbo-9 code in 2.1.131: do_gettimeofday was missing 1 jiffy
- * because was not accounting lost_ticks.
- * 1998-12-24 Copyright (C) 1998 Andrea Arcangeli
- * Fixed a xtime SMP race (we need the xtime_lock rw spinlock to
- * serialize accesses to xtime/lost_ticks).
- */
-
-#include <asm/smp.h>
-#include <asm/irq.h>
-#include <asm/msr.h>
-#include <asm/delay.h>
-#include <asm/mpspec.h>
-#include <asm/uaccess.h>
-#include <asm/processor.h>
-
-#include <asm/div64.h>
-#include <asm/hypervisor.h>
-
-#include <linux/kernel.h>
-#include <linux/interrupt.h>
-#include <linux/time.h>
-#include <linux/init.h>
-#include <linux/smp.h>
-#include <linux/irq.h>
-
-#undef XENO_TIME_DEBUG /* adds sanity checks and periodic printouts */
-
-spinlock_t rtc_lock = SPIN_LOCK_UNLOCKED;
-extern rwlock_t xtime_lock;
-
-unsigned long cpu_khz; /* get this from Xen, used elsewhere */
-static spinlock_t hyp_stime_lock = SPIN_LOCK_UNLOCKED;
-static spinlock_t hyp_wctime_lock = SPIN_LOCK_UNLOCKED;
-
-static u32 st_scale_f;
-static u32 st_scale_i;
-static u32 shadow_st_pcc;
-static s64 shadow_st;
-
-/*
- * System time.
- * Although the rest of the Linux kernel doesn't know about this, we
- * we use it to extrapolate passage of wallclock time.
- * We need to read the values from the shared info page "atomically"
- * and use the cycle counter value as the "version" number. Clashes
- * should be very rare.
- */
-static inline long long get_s_time(void)
-{
- unsigned long flags;
- u32 delta_tsc, low, pcc;
- u64 delta;
- s64 now;
-
- spin_lock_irqsave(&hyp_stime_lock, flags);
-
- while ((pcc = HYPERVISOR_shared_info->st_timestamp) != shadow_st_pcc)
- {
- barrier();
- shadow_st_pcc = pcc;
- shadow_st = HYPERVISOR_shared_info->system_time;
- barrier();
- }
-
- now = shadow_st;
- /* only use bottom 32bits of TSC. This should be sufficient */
- rdtscl(low);
- delta_tsc = low - pcc;
- delta = ((u64)delta_tsc * st_scale_f);
- delta >>= 32;
- delta += ((u64)delta_tsc * st_scale_i);
-
- spin_unlock_irqrestore(&hyp_time_lock, flags);
-
- return now + delta;
-
-}
-#define NOW() ((long long)get_s_time())
-
-/*
- * Wallclock time.
- * Based on what the hypervisor tells us, extrapolated using system time.
- * Again need to read a number of values from the shared page "atomically".
- * this time using a version number.
- */
-static u32 shadow_wc_version=0;
-static long shadow_tv_sec;
-static long shadow_tv_usec;
-static long long shadow_wc_timestamp;
-void do_gettimeofday(struct timeval *tv)
-{
- unsigned long flags;
- long usec, sec;
- u32 version;
- u64 now;
-
- spin_lock_irqsave(&hyp_wctime_lock, flags);
-
- while ((version = HYPERVISOR_shared_info->wc_version)!= shadow_wc_version)
- {
- barrier();
- shadow_wc_version = version;
- shadow_tv_sec = HYPERVISOR_shared_info->tv_sec;
- shadow_tv_usec = HYPERVISOR_shared_info->tv_usec;
- shadow_wc_timestamp = HYPERVISOR_shared_info->wc_timestamp;
- barrier();
- }
-
- now = NOW();
- usec = ((unsigned long)(now-shadow_wc_timestamp))/1000;
- sec = shadow_tv_sec;
- usec += shadow_tv_usec;
-
- while ( usec >= 1000000 )
- {
- usec -= 1000000;
- sec++;
- }
-
- tv->tv_sec = sec;
- tv->tv_usec = usec;
-
- spin_unlock_irqrestore(&hyp_time_lock, flags);
-
-#ifdef XENO_TIME_DEBUG
- {
- static long long old_now=0;
- static long long wct=0, old_wct=0;
-
- /* This debug code checks if time increase over two subsequent calls */
- wct=(((long long)sec) * 1000000) + usec;
- /* wall clock time going backwards */
- if ((wct < old_wct) ) {
- printk("Urgh1: wc diff=%6ld, usec = %ld (0x%lX)\n",
- (long)(wct-old_wct), usec, usec);
- printk(" st diff=%lld cur st=0x%016llX old st=0x%016llX\n",
- now-old_now, now, old_now);
- }
-
- /* system time going backwards */
- if (now<=old_now) {
- printk("Urgh2: st diff=%lld cur st=0x%016llX old st=0x%016llX\n",
- now-old_now, now, old_now);
- }
- old_wct = wct;
- old_now = now;
- }
-#endif
-
-}
-
-void do_settimeofday(struct timeval *tv)
-{
-/* XXX RN: should do something special here for dom0 */
-#if 0
- write_lock_irq(&xtime_lock);
- /*
- * This is revolting. We need to set "xtime" correctly. However, the
- * value in this location is the value at the most recent update of
- * wall time. Discover what correction gettimeofday() would have
- * made, and then undo it!
- */
- tv->tv_usec -= do_gettimeoffset();
- tv->tv_usec -= (jiffies - wall_jiffies) * (1000000 / HZ);
-
- while ( tv->tv_usec < 0 )
- {
- tv->tv_usec += 1000000;
- tv->tv_sec--;
- }
-
- xtime = *tv;
- time_adjust = 0; /* stop active adjtime() */
- time_status |= STA_UNSYNC;
- time_maxerror = NTP_PHASE_LIMIT;
- time_esterror = NTP_PHASE_LIMIT;
- write_unlock_irq(&xtime_lock);
-#endif
-}
-
-
-/*
- * Timer ISR.
- * Unlike normal Linux these don't come in at a fixed rate of HZ.
- * In here we wrok out how often it should have been called and then call
- * the architecture independent part (do_timer()) the appropriate number of
- * times. A bit of a nasty hack, to keep the "other" notion of wallclock time
- * happy.
- */
-static long long us_per_tick=1000000/HZ;
-static long long last_irq;
-static inline void do_timer_interrupt(int irq, void *dev_id,
- struct pt_regs *regs)
-{
- struct timeval tv;
- long long time, delta;
-
-#ifdef XENO_TIME_DEBUG
- static u32 foo_count = 0;
- foo_count++;
- if (foo_count>= 1000) {
- s64 n = NOW();
- struct timeval tv;
- do_gettimeofday(&tv);
- printk("0x%08X%08X %ld:%ld\n",
- (u32)(n>>32), (u32)n, tv.tv_sec, tv.tv_usec);
- foo_count = 0;
- }
-#endif
- /*
- * The next bit really sucks:
- * Linux not only uses do_gettimeofday() to keep a notion of
- * wallclock time, but also maintains the xtime struct and jiffies.
- * (Even worse some userland code accesses this via the sys_time()
- * system call)
- * Unfortunately, xtime is maintain in the architecture independent
- * part of the timer ISR (./kernel/timer.c sic!). So, although we have
- * perfectly valid notion of wallclock time from the hypervisor we here
- * fake missed timer interrupts so that the arch independent part of
- * the Timer ISR updates jiffies for us *and* once the bh gets run
- * updates xtime accordingly. Yuck!
- */
-
- /* work out the number of jiffies past and update them */
- do_gettimeofday(&tv);
- time = (((long long)tv.tv_sec) * 1000000) + tv.tv_usec;
- delta = time - last_irq;
- if (delta <= 0) {
- printk ("Timer ISR: Time went backwards: %lld\n", delta);
- return;
- }
- while (delta >= us_per_tick) {
- do_timer(regs);
- delta -= us_per_tick;
- last_irq += us_per_tick;
- }
-
-#if 0
- if (!user_mode(regs))
- x86_do_profile(regs->eip);
-#endif
-}
-
-static void timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
-{
- write_lock(&xtime_lock);
- do_timer_interrupt(irq, NULL, regs);
- write_unlock(&xtime_lock);
-}
-
-static struct irqaction irq_timer = {
- timer_interrupt,
- SA_INTERRUPT,
- 0,
- "timer",
- NULL,
- NULL
-};
-
-void __init time_init(void)
-{
- unsigned long long alarm;
- u64 cpu_freq = HYPERVISOR_shared_info->cpu_freq;
- u64 scale;
-
- cpu_khz = (u32)cpu_freq/1000;
- printk("Xen reported: %lu.%03lu MHz processor.\n",
- cpu_khz / 1000, cpu_khz % 1000);
-
- /*
- * calculate systemtime scaling factor
- * XXX RN: have to cast cpu_freq to u32 limits it to 4.29 GHz.
- * Get a better do_div!
- */
- scale = 1000000000LL << 32;
- do_div(scale,(u32)cpu_freq);
- st_scale_f = scale & 0xffffffff;
- st_scale_i = scale >> 32;
- printk("System Time scale: %X %X\n",st_scale_i, st_scale_f);
-
- do_gettimeofday(&xtime);
- last_irq = (((long long)xtime.tv_sec) * 1000000) + xtime.tv_usec;
-
- setup_irq(TIMER_IRQ, &irq_timer);
-
- /*
- * Start ticker. Note that timing runs of wall clock, not virtual
- * 'domain' time. This means that clock sshould run at the correct
- * rate. For things like scheduling, it's not clear whether it
- * matters which sort of time we use.
- * XXX RN: unimplemented.
- */
-
- rdtscll(alarm);
-#if 0
- alarm += (1000/HZ)*HYPERVISOR_shared_info->ticks_per_ms;
- HYPERVISOR_shared_info->wall_timeout = alarm;
- HYPERVISOR_shared_info->domain_timeout = ~0ULL;
-#endif
- clear_bit(_EVENT_TIMER, &HYPERVISOR_shared_info->events);
-}
+++ /dev/null
-/*
- * linux/arch/i386/traps.c
- *
- * Copyright (C) 1991, 1992 Linus Torvalds
- *
- * Pentium III FXSR, SSE support
- * Gareth Hughes <gareth@valinux.com>, May 2000
- */
-
-/*
- * 'Traps.c' handles hardware traps and faults after we have saved some
- * state in 'asm.s'.
- */
-#include <linux/config.h>
-#include <linux/sched.h>
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/errno.h>
-#include <linux/ptrace.h>
-#include <linux/timer.h>
-#include <linux/mm.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/spinlock.h>
-#include <linux/interrupt.h>
-#include <linux/highmem.h>
-
-#include <asm/system.h>
-#include <asm/uaccess.h>
-#include <asm/io.h>
-#include <asm/atomic.h>
-#include <asm/debugreg.h>
-#include <asm/desc.h>
-#include <asm/i387.h>
-
-#include <asm/smp.h>
-#include <asm/pgalloc.h>
-
-#include <asm/hypervisor.h>
-
-#include <linux/irq.h>
-#include <linux/module.h>
-
-asmlinkage int system_call(void);
-asmlinkage void lcall7(void);
-asmlinkage void lcall27(void);
-
-asmlinkage void divide_error(void);
-asmlinkage void debug(void);
-asmlinkage void int3(void);
-asmlinkage void overflow(void);
-asmlinkage void bounds(void);
-asmlinkage void invalid_op(void);
-asmlinkage void device_not_available(void);
-asmlinkage void double_fault(void);
-asmlinkage void coprocessor_segment_overrun(void);
-asmlinkage void invalid_TSS(void);
-asmlinkage void segment_not_present(void);
-asmlinkage void stack_segment(void);
-asmlinkage void general_protection(void);
-asmlinkage void page_fault(void);
-asmlinkage void coprocessor_error(void);
-asmlinkage void simd_coprocessor_error(void);
-asmlinkage void alignment_check(void);
-asmlinkage void spurious_interrupt_bug(void);
-asmlinkage void machine_check(void);
-
-int kstack_depth_to_print = 24;
-
-
-/*
- * If the address is either in the .text section of the
- * kernel, or in the vmalloc'ed module regions, it *may*
- * be the address of a calling routine
- */
-
-#ifdef CONFIG_MODULES
-
-extern struct module *module_list;
-extern struct module kernel_module;
-
-static inline int kernel_text_address(unsigned long addr)
-{
- int retval = 0;
- struct module *mod;
-
- if (addr >= (unsigned long) &_stext &&
- addr <= (unsigned long) &_etext)
- return 1;
-
- for (mod = module_list; mod != &kernel_module; mod = mod->next) {
- /* mod_bound tests for addr being inside the vmalloc'ed
- * module area. Of course it'd be better to test only
- * for the .text subset... */
- if (mod_bound(addr, 0, mod)) {
- retval = 1;
- break;
- }
- }
-
- return retval;
-}
-
-#else
-
-static inline int kernel_text_address(unsigned long addr)
-{
- return (addr >= (unsigned long) &_stext &&
- addr <= (unsigned long) &_etext);
-}
-
-#endif
-
-void show_trace(unsigned long * stack)
-{
- int i;
- unsigned long addr;
-
- if (!stack)
- stack = (unsigned long*)&stack;
-
- printk("Call Trace: ");
- i = 1;
- while (((long) stack & (THREAD_SIZE-1)) != 0) {
- addr = *stack++;
- if (kernel_text_address(addr)) {
- if (i && ((i % 6) == 0))
- printk("\n ");
- printk("[<%08lx>] ", addr);
- i++;
- }
- }
- printk("\n");
-}
-
-void show_trace_task(struct task_struct *tsk)
-{
- unsigned long esp = tsk->thread.esp;
-
- /* User space on another CPU? */
- if ((esp ^ (unsigned long)tsk) & (PAGE_MASK<<1))
- return;
- show_trace((unsigned long *)esp);
-}
-
-void show_stack(unsigned long * esp)
-{
- unsigned long *stack;
- int i;
-
- // debugging aid: "show_stack(NULL);" prints the
- // back trace for this cpu.
-
- if(esp==NULL)
- esp=(unsigned long*)&esp;
-
- stack = esp;
- for(i=0; i < kstack_depth_to_print; i++) {
- if (((long) stack & (THREAD_SIZE-1)) == 0)
- break;
- if (i && ((i % 8) == 0))
- printk("\n ");
- printk("%08lx ", *stack++);
- }
- printk("\n");
- show_trace(esp);
-}
-
-void show_registers(struct pt_regs *regs)
-{
- int i;
- int in_kernel = 1;
- unsigned long esp;
- unsigned short ss;
-
- esp = (unsigned long) (®s->esp);
- ss = __KERNEL_DS;
- if (regs->xcs & 2) {
- in_kernel = 0;
- esp = regs->esp;
- ss = regs->xss & 0xffff;
- }
- printk("CPU: %d\nEIP: %04x:[<%08lx>] %s\nEFLAGS: %08lx\n",
- smp_processor_id(), 0xffff & regs->xcs, regs->eip, print_tainted(), regs->eflags);
- printk("eax: %08lx ebx: %08lx ecx: %08lx edx: %08lx\n",
- regs->eax, regs->ebx, regs->ecx, regs->edx);
- printk("esi: %08lx edi: %08lx ebp: %08lx esp: %08lx\n",
- regs->esi, regs->edi, regs->ebp, esp);
- printk("ds: %04x es: %04x ss: %04x\n",
- regs->xds & 0xffff, regs->xes & 0xffff, ss);
- printk("Process %s (pid: %d, stackpage=%08lx)",
- current->comm, current->pid, 4096+(unsigned long)current);
- /*
- * When in-kernel, we also print out the stack and code at the
- * time of the fault..
- */
- if (in_kernel) {
-
- printk("\nStack: ");
- show_stack((unsigned long*)esp);
-
-#if 0
- printk("\nCode: ");
- if(regs->eip < PAGE_OFFSET)
- goto bad;
-
- for(i=0;i<20;i++)
- {
- unsigned char c;
- if(__get_user(c, &((unsigned char*)regs->eip)[i])) {
-bad:
- printk(" Bad EIP value.");
- break;
- }
- printk("%02x ", c);
- }
-#endif
- }
- printk("\n");
-}
-
-spinlock_t die_lock = SPIN_LOCK_UNLOCKED;
-
-void die(const char * str, struct pt_regs * regs, long err)
-{
- console_verbose();
- spin_lock_irq(&die_lock);
- bust_spinlocks(1);
- printk("%s: %04lx\n", str, err & 0xffff);
- show_registers(regs);
- bust_spinlocks(0);
- spin_unlock_irq(&die_lock);
- do_exit(SIGSEGV);
-}
-
-static inline void die_if_kernel(const char * str, struct pt_regs * regs, long err)
-{
- if (!(2 & regs->xcs))
- die(str, regs, err);
-}
-
-
-static void inline do_trap(int trapnr, int signr, char *str,
- struct pt_regs * regs, long error_code,
- siginfo_t *info)
-{
- if (!(regs->xcs & 2))
- goto kernel_trap;
-
- /*trap_signal:*/ {
- struct task_struct *tsk = current;
- tsk->thread.error_code = error_code;
- tsk->thread.trap_no = trapnr;
- if (info)
- force_sig_info(signr, info, tsk);
- else
- force_sig(signr, tsk);
- return;
- }
-
- kernel_trap: {
- unsigned long fixup = search_exception_table(regs->eip);
- if (fixup)
- regs->eip = fixup;
- else
- die(str, regs, error_code);
- return;
- }
-}
-
-#define DO_ERROR(trapnr, signr, str, name) \
-asmlinkage void do_##name(struct pt_regs * regs, long error_code) \
-{ \
- do_trap(trapnr, signr, str, regs, error_code, NULL); \
-}
-
-#define DO_ERROR_INFO(trapnr, signr, str, name, sicode, siaddr) \
-asmlinkage void do_##name(struct pt_regs * regs, long error_code) \
-{ \
- siginfo_t info; \
- info.si_signo = signr; \
- info.si_errno = 0; \
- info.si_code = sicode; \
- info.si_addr = (void *)siaddr; \
- do_trap(trapnr, signr, str, regs, error_code, &info); \
-}
-
-DO_ERROR_INFO( 0, SIGFPE, "divide error", divide_error, FPE_INTDIV, regs->eip)
-DO_ERROR( 3, SIGTRAP, "int3", int3)
-DO_ERROR( 4, SIGSEGV, "overflow", overflow)
-DO_ERROR( 5, SIGSEGV, "bounds", bounds)
-DO_ERROR_INFO( 6, SIGILL, "invalid operand", invalid_op, ILL_ILLOPN, regs->eip)
-DO_ERROR( 7, SIGSEGV, "device not available", device_not_available)
-DO_ERROR( 8, SIGSEGV, "double fault", double_fault)
-DO_ERROR( 9, SIGFPE, "coprocessor segment overrun", coprocessor_segment_overrun)
-DO_ERROR(10, SIGSEGV, "invalid TSS", invalid_TSS)
-DO_ERROR(11, SIGBUS, "segment not present", segment_not_present)
-DO_ERROR(12, SIGBUS, "stack segment", stack_segment)
-DO_ERROR_INFO(17, SIGBUS, "alignment check", alignment_check, BUS_ADRALN, 0)
-DO_ERROR(18, SIGBUS, "machine check", machine_check)
-
-asmlinkage void do_general_protection(struct pt_regs * regs, long error_code)
-{
- if (!(regs->xcs & 2))
- goto gp_in_kernel;
-
- current->thread.error_code = error_code;
- current->thread.trap_no = 13;
- force_sig(SIGSEGV, current);
- return;
-
-gp_in_kernel:
- {
- unsigned long fixup;
- fixup = search_exception_table(regs->eip);
- if (fixup) {
- regs->eip = fixup;
- return;
- }
- die("general protection fault", regs, error_code);
- }
-}
-
-
-asmlinkage void do_debug(struct pt_regs * regs, long error_code)
-{
- unsigned int condition;
- struct task_struct *tsk = current;
- siginfo_t info;
-
- condition = HYPERVISOR_get_debugreg(6);
-
- /* Mask out spurious debug traps due to lazy DR7 setting */
- if (condition & (DR_TRAP0|DR_TRAP1|DR_TRAP2|DR_TRAP3)) {
- if (!tsk->thread.debugreg[7])
- goto clear_dr7;
- }
-
- /* Save debug status register where ptrace can see it */
- tsk->thread.debugreg[6] = condition;
-
- /* Mask out spurious TF errors due to lazy TF clearing */
- if (condition & DR_STEP) {
- /*
- * The TF error should be masked out only if the current
- * process is not traced and if the TRAP flag has been set
- * previously by a tracing process (condition detected by
- * the PT_DTRACE flag); remember that the i386 TRAP flag
- * can be modified by the process itself in user mode,
- * allowing programs to debug themselves without the ptrace()
- * interface.
- */
- if ((tsk->ptrace & (PT_DTRACE|PT_PTRACED)) == PT_DTRACE)
- goto clear_TF;
- }
-
- /* Ok, finally something we can handle */
- tsk->thread.trap_no = 1;
- tsk->thread.error_code = error_code;
- info.si_signo = SIGTRAP;
- info.si_errno = 0;
- info.si_code = TRAP_BRKPT;
-
- /* If this is a kernel mode trap, save the user PC on entry to
- * the kernel, that's what the debugger can make sense of.
- */
- info.si_addr = ((regs->xcs & 2) == 0) ? (void *)tsk->thread.eip :
- (void *)regs->eip;
- force_sig_info(SIGTRAP, &info, tsk);
-
- /* Disable additional traps. They'll be re-enabled when
- * the signal is delivered.
- */
- clear_dr7:
- HYPERVISOR_set_debugreg(7, 0);
- return;
-
- clear_TF:
- regs->eflags &= ~TF_MASK;
- return;
-}
-
-
-/*
- * Note that we play around with the 'TS' bit in an attempt to get
- * the correct behaviour even in the presence of the asynchronous
- * IRQ13 behaviour
- */
-void math_error(void *eip)
-{
- struct task_struct * task;
- siginfo_t info;
- unsigned short cwd, swd;
-
- /*
- * Save the info for the exception handler and clear the error.
- */
- task = current;
- save_init_fpu(task);
- task->thread.trap_no = 16;
- task->thread.error_code = 0;
- info.si_signo = SIGFPE;
- info.si_errno = 0;
- info.si_code = __SI_FAULT;
- info.si_addr = eip;
- /*
- * (~cwd & swd) will mask out exceptions that are not set to unmasked
- * status. 0x3f is the exception bits in these regs, 0x200 is the
- * C1 reg you need in case of a stack fault, 0x040 is the stack
- * fault bit. We should only be taking one exception at a time,
- * so if this combination doesn't produce any single exception,
- * then we have a bad program that isn't syncronizing its FPU usage
- * and it will suffer the consequences since we won't be able to
- * fully reproduce the context of the exception
- */
- cwd = get_fpu_cwd(task);
- swd = get_fpu_swd(task);
- switch (((~cwd) & swd & 0x3f) | (swd & 0x240)) {
- case 0x000:
- default:
- break;
- case 0x001: /* Invalid Op */
- case 0x040: /* Stack Fault */
- case 0x240: /* Stack Fault | Direction */
- info.si_code = FPE_FLTINV;
- break;
- case 0x002: /* Denormalize */
- case 0x010: /* Underflow */
- info.si_code = FPE_FLTUND;
- break;
- case 0x004: /* Zero Divide */
- info.si_code = FPE_FLTDIV;
- break;
- case 0x008: /* Overflow */
- info.si_code = FPE_FLTOVF;
- break;
- case 0x020: /* Precision */
- info.si_code = FPE_FLTRES;
- break;
- }
- force_sig_info(SIGFPE, &info, task);
-}
-
-asmlinkage void do_coprocessor_error(struct pt_regs * regs, long error_code)
-{
- ignore_irq13 = 1;
- math_error((void *)regs->eip);
-}
-
-void simd_math_error(void *eip)
-{
- struct task_struct * task;
- siginfo_t info;
- unsigned short mxcsr;
-
- /*
- * Save the info for the exception handler and clear the error.
- */
- task = current;
- save_init_fpu(task);
- task->thread.trap_no = 19;
- task->thread.error_code = 0;
- info.si_signo = SIGFPE;
- info.si_errno = 0;
- info.si_code = __SI_FAULT;
- info.si_addr = eip;
- /*
- * The SIMD FPU exceptions are handled a little differently, as there
- * is only a single status/control register. Thus, to determine which
- * unmasked exception was caught we must mask the exception mask bits
- * at 0x1f80, and then use these to mask the exception bits at 0x3f.
- */
- mxcsr = get_fpu_mxcsr(task);
- switch (~((mxcsr & 0x1f80) >> 7) & (mxcsr & 0x3f)) {
- case 0x000:
- default:
- break;
- case 0x001: /* Invalid Op */
- info.si_code = FPE_FLTINV;
- break;
- case 0x002: /* Denormalize */
- case 0x010: /* Underflow */
- info.si_code = FPE_FLTUND;
- break;
- case 0x004: /* Zero Divide */
- info.si_code = FPE_FLTDIV;
- break;
- case 0x008: /* Overflow */
- info.si_code = FPE_FLTOVF;
- break;
- case 0x020: /* Precision */
- info.si_code = FPE_FLTRES;
- break;
- }
- force_sig_info(SIGFPE, &info, task);
-}
-
-asmlinkage void do_simd_coprocessor_error(struct pt_regs * regs,
- long error_code)
-{
- if (cpu_has_xmm) {
- /* Handle SIMD FPU exceptions on PIII+ processors. */
- ignore_irq13 = 1;
- simd_math_error((void *)regs->eip);
- } else {
- die_if_kernel("cache flush denied", regs, error_code);
- current->thread.trap_no = 19;
- current->thread.error_code = error_code;
- force_sig(SIGSEGV, current);
- }
-}
-
-asmlinkage void do_spurious_interrupt_bug(struct pt_regs * regs,
- long error_code)
-{
-}
-
-/*
- * 'math_state_restore()' saves the current math information in the
- * old math state array, and gets the new ones from the current task
- *
- * Careful.. There are problems with IBM-designed IRQ13 behaviour.
- * Don't touch unless you *really* know how it works.
- */
-asmlinkage void math_state_restore(struct pt_regs regs)
-{
- if (current->used_math) {
- restore_fpu(current);
- } else {
- init_fpu();
- }
- current->flags |= PF_USEDFPU; /* So we fnsave on switch_to() */
-}
-
-
-#define _set_gate(gate_addr,type,dpl,addr) \
-do { \
- int __d0, __d1; \
- __asm__ __volatile__ ("movw %%dx,%%ax\n\t" \
- "movw %4,%%dx\n\t" \
- "movl %%eax,%0\n\t" \
- "movl %%edx,%1" \
- :"=m" (*((long *) (gate_addr))), \
- "=m" (*(1+(long *) (gate_addr))), "=&a" (__d0), "=&d" (__d1) \
- :"i" ((short) (0x8000+(dpl<<13)+(type<<8))), \
- "3" ((char *) (addr)),"2" (__KERNEL_CS << 16)); \
-} while (0)
-
-static void __init set_call_gate(void *a, void *addr)
-{
- _set_gate(a,12,3,addr);
-}
-
-
-static trap_info_t trap_table[] = {
- { 0, 0, __KERNEL_CS, (unsigned long)divide_error },
- { 1, 0, __KERNEL_CS, (unsigned long)debug },
- { 3, 3, __KERNEL_CS, (unsigned long)int3 },
- { 4, 3, __KERNEL_CS, (unsigned long)overflow },
- { 5, 3, __KERNEL_CS, (unsigned long)bounds },
- { 6, 0, __KERNEL_CS, (unsigned long)invalid_op },
- { 7, 0, __KERNEL_CS, (unsigned long)device_not_available },
- { 8, 0, __KERNEL_CS, (unsigned long)double_fault },
- { 9, 0, __KERNEL_CS, (unsigned long)coprocessor_segment_overrun },
- { 10, 0, __KERNEL_CS, (unsigned long)invalid_TSS },
- { 11, 0, __KERNEL_CS, (unsigned long)segment_not_present },
- { 12, 0, __KERNEL_CS, (unsigned long)stack_segment },
- { 13, 0, __KERNEL_CS, (unsigned long)general_protection },
- { 14, 0, __KERNEL_CS, (unsigned long)page_fault },
- { 15, 0, __KERNEL_CS, (unsigned long)spurious_interrupt_bug },
- { 16, 0, __KERNEL_CS, (unsigned long)coprocessor_error },
- { 17, 0, __KERNEL_CS, (unsigned long)alignment_check },
- { 18, 0, __KERNEL_CS, (unsigned long)machine_check },
- { 19, 0, __KERNEL_CS, (unsigned long)simd_coprocessor_error },
- { SYSCALL_VECTOR,
- 3, __KERNEL_CS, (unsigned long)system_call },
- { 0, 0, 0, 0 }
-};
-
-
-
-void __init trap_init(void)
-{
- HYPERVISOR_set_trap_table(trap_table);
- HYPERVISOR_set_fast_trap(SYSCALL_VECTOR);
-
- /*
- * The default LDT is a single-entry callgate to lcall7 for iBCS and a
- * callgate to lcall27 for Solaris/x86 binaries.
- */
- clear_page(&default_ldt[0]);
- set_call_gate(&default_ldt[0],lcall7);
- set_call_gate(&default_ldt[4],lcall27);
- __make_page_readonly(&default_ldt[0]);
-
- cpu_init();
-}
+++ /dev/null
-
-.S.o:
- $(CC) $(AFLAGS) -c $< -o $*.o
-
-L_TARGET = lib.a
-
-obj-y = checksum.o old-checksum.o delay.o \
- usercopy.o getuser.o \
- memcpy.o strstr.o
-
-obj-$(CONFIG_X86_USE_3DNOW) += mmx.o
-obj-$(CONFIG_HAVE_DEC_LOCK) += dec_and_lock.o
-obj-$(CONFIG_DEBUG_IOVIRT) += iodebug.o
-
-include $(TOPDIR)/Rules.make
+++ /dev/null
-/*
- * Precise Delay Loops for i386
- *
- * Copyright (C) 1993 Linus Torvalds
- * Copyright (C) 1997 Martin Mares <mj@atrey.karlin.mff.cuni.cz>
- *
- * The __delay function must _NOT_ be inlined as its execution time
- * depends wildly on alignment on many x86 processors. The additional
- * jump magic is needed to get the timing stable on all the CPU's
- * we have to worry about.
- */
-
-#include <linux/config.h>
-#include <linux/sched.h>
-#include <linux/delay.h>
-#include <asm/processor.h>
-#include <asm/delay.h>
-
-#ifdef CONFIG_SMP
-#include <asm/smp.h>
-#endif
-
-void __delay(unsigned long loops)
-{
- unsigned long bclock, now;
-
- rdtscl(bclock);
- do
- {
- rep_nop();
- rdtscl(now);
- } while ((now-bclock) < loops);
-}
-
-inline void __const_udelay(unsigned long xloops)
-{
- int d0;
- __asm__("mull %0"
- :"=d" (xloops), "=&a" (d0)
- :"1" (xloops),"0" (current_cpu_data.loops_per_jiffy));
- __delay(xloops * HZ);
-}
-
-void __udelay(unsigned long usecs)
-{
- __const_udelay(usecs * 0x000010c6); /* 2**32 / 1000000 */
-}
+++ /dev/null
-#
-# Makefile for the linux i386-specific parts of the memory manager.
-#
-# Note! Dependencies are done automagically by 'make dep', which also
-# removes any old dependencies. DON'T put your own dependencies here
-# unless it's something special (ie not a .c file).
-#
-# Note 2! The CFLAGS definition is now in the main makefile...
-
-O_TARGET := mm.o
-
-obj-y := init.o fault.o extable.o pageattr.o hypervisor.o get_unmapped_area.o mmu_context.o
-
-export-objs := pageattr.o
-
-include $(TOPDIR)/Rules.make
+++ /dev/null
-/*
- * linux/arch/i386/mm/fault.c
- *
- * Copyright (C) 1995 Linus Torvalds
- */
-
-#include <linux/signal.h>
-#include <linux/sched.h>
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/string.h>
-#include <linux/types.h>
-#include <linux/ptrace.h>
-#include <linux/mman.h>
-#include <linux/mm.h>
-#include <linux/smp.h>
-#include <linux/smp_lock.h>
-#include <linux/interrupt.h>
-#include <linux/init.h>
-#include <linux/tty.h>
-#include <linux/vt_kern.h> /* For unblank_screen() */
-
-#include <asm/system.h>
-#include <asm/uaccess.h>
-#include <asm/pgalloc.h>
-#include <asm/hardirq.h>
-
-extern void die(const char *,struct pt_regs *,long);
-
-pgd_t *cur_pgd;
-
-/*
- * Ugly, ugly, but the goto's result in better assembly..
- */
-int __verify_write(const void * addr, unsigned long size)
-{
- struct vm_area_struct * vma;
- unsigned long start = (unsigned long) addr;
-
- if (!size)
- return 1;
-
- vma = find_vma(current->mm, start);
- if (!vma)
- goto bad_area;
- if (vma->vm_start > start)
- goto check_stack;
-
-good_area:
- if (!(vma->vm_flags & VM_WRITE))
- goto bad_area;
- size--;
- size += start & ~PAGE_MASK;
- size >>= PAGE_SHIFT;
- start &= PAGE_MASK;
-
- for (;;) {
- survive:
- {
- int fault = handle_mm_fault(current->mm, vma, start, 1);
- if (!fault)
- goto bad_area;
- if (fault < 0)
- goto out_of_memory;
- }
- if (!size)
- break;
- size--;
- start += PAGE_SIZE;
- if (start < vma->vm_end)
- continue;
- vma = vma->vm_next;
- if (!vma || vma->vm_start != start)
- goto bad_area;
- if (!(vma->vm_flags & VM_WRITE))
- goto bad_area;;
- }
- return 1;
-
-check_stack:
- if (!(vma->vm_flags & VM_GROWSDOWN))
- goto bad_area;
- if (expand_stack(vma, start) == 0)
- goto good_area;
-
-bad_area:
- return 0;
-
-out_of_memory:
- if (current->pid == 1) {
- yield();
- goto survive;
- }
- goto bad_area;
-}
-
-extern spinlock_t timerlist_lock;
-
-/*
- * Unlock any spinlocks which will prevent us from getting the
- * message out (timerlist_lock is acquired through the
- * console unblank code)
- */
-void bust_spinlocks(int yes)
-{
- spin_lock_init(&timerlist_lock);
- if (yes) {
- oops_in_progress = 1;
- } else {
- int loglevel_save = console_loglevel;
-#ifdef CONFIG_VT
- unblank_screen();
-#endif
- oops_in_progress = 0;
- /*
- * OK, the message is on the console. Now we call printk()
- * without oops_in_progress set so that printk will give klogd
- * a poke. Hold onto your hats...
- */
- console_loglevel = 15; /* NMI oopser may have shut the console up */
- printk(" ");
- console_loglevel = loglevel_save;
- }
-}
-
-/*
- * This routine handles page faults. It determines the address,
- * and the problem, and then passes it off to one of the appropriate
- * routines.
- *
- * error_code:
- * bit 0 == 0 means no page found, 1 means protection fault
- * bit 1 == 0 means read, 1 means write
- * bit 2 == 0 means kernel, 1 means user-mode
- */
-asmlinkage void do_page_fault(struct pt_regs *regs,
- unsigned long error_code,
- unsigned long address)
-{
- struct task_struct *tsk = current;
- struct mm_struct *mm;
- struct vm_area_struct * vma;
- unsigned long page;
- unsigned long fixup;
- int write;
- siginfo_t info;
-
- /* Set the "privileged fault" bit to something sane. */
- error_code &= 3;
- error_code |= (regs->xcs & 2) << 1;
-
-#if PT_UPDATE_DEBUG > 0
- if ( (error_code == 0) && (address >= TASK_SIZE) )
- {
- unsigned long paddr = __pa(address);
- int i;
- for ( i = 0; i < pt_update_queue_idx; i++ )
- {
- if ( update_debug_queue[i].ptr == paddr )
- {
- printk("XXX now(EIP=%08lx:ptr=%08lx) "
- "then(%s/%d:p/v=%08lx/%08lx)\n",
- regs->eip, address,
- update_debug_queue[i].file,
- update_debug_queue[i].line,
- update_debug_queue[i].ptr,
- update_debug_queue[i].val);
- }
- }
- }
-#endif
-
- if ( flush_page_update_queue() != 0 ) return;
-
- /*
- * We fault-in kernel-space virtual memory on-demand. The
- * 'reference' page table is init_mm.pgd.
- *
- * NOTE! We MUST NOT take any locks for this case. We may
- * be in an interrupt or a critical region, and should
- * only copy the information from the master page table,
- * nothing more.
- *
- * This verifies that the fault happens in kernel space
- * (error_code & 4) == 0, and that the fault was not a
- * protection error (error_code & 1) == 0.
- */
- if (address >= TASK_SIZE && !(error_code & 5))
- goto vmalloc_fault;
-
- mm = tsk->mm;
- info.si_code = SEGV_MAPERR;
-
- /*
- * If we're in an interrupt or have no user
- * context, we must not take the fault..
- */
- if (in_interrupt() || !mm)
- goto no_context;
-
- down_read(&mm->mmap_sem);
-
- vma = find_vma(mm, address);
- if (!vma)
- goto bad_area;
- if (vma->vm_start <= address)
- goto good_area;
- if (!(vma->vm_flags & VM_GROWSDOWN))
- goto bad_area;
- if (error_code & 4) {
- /*
- * accessing the stack below %esp is always a bug.
- * The "+ 32" is there due to some instructions (like
- * pusha) doing post-decrement on the stack and that
- * doesn't show up until later..
- */
- if (address + 32 < regs->esp)
- goto bad_area;
- }
- if (expand_stack(vma, address))
- goto bad_area;
-/*
- * Ok, we have a good vm_area for this memory access, so
- * we can handle it..
- */
-good_area:
- info.si_code = SEGV_ACCERR;
- write = 0;
- switch (error_code & 3) {
- default: /* 3: write, present */
- /* fall through */
- case 2: /* write, not present */
- if (!(vma->vm_flags & VM_WRITE))
- goto bad_area;
- write++;
- break;
- case 1: /* read, present */
- goto bad_area;
- case 0: /* read, not present */
- if (!(vma->vm_flags & (VM_READ | VM_EXEC)))
- goto bad_area;
- }
-
- survive:
- /*
- * If for any reason at all we couldn't handle the fault,
- * make sure we exit gracefully rather than endlessly redo
- * the fault.
- */
- switch (handle_mm_fault(mm, vma, address, write)) {
- case 1:
- tsk->min_flt++;
- break;
- case 2:
- tsk->maj_flt++;
- break;
- case 0:
- goto do_sigbus;
- default:
- goto out_of_memory;
- }
-
- up_read(&mm->mmap_sem);
- return;
-
-/*
- * Something tried to access memory that isn't in our memory map..
- * Fix it, but check if it's kernel or user first..
- */
-bad_area:
- up_read(&mm->mmap_sem);
-
- /* User mode accesses just cause a SIGSEGV */
- if (error_code & 4) {
- tsk->thread.cr2 = address;
- tsk->thread.error_code = error_code;
- tsk->thread.trap_no = 14;
- info.si_signo = SIGSEGV;
- info.si_errno = 0;
- /* info.si_code has been set above */
- info.si_addr = (void *)address;
- force_sig_info(SIGSEGV, &info, tsk);
- return;
- }
-
-no_context:
- /* Are we prepared to handle this kernel fault? */
- if ((fixup = search_exception_table(regs->eip)) != 0) {
- regs->eip = fixup;
- return;
- }
-
-/*
- * Oops. The kernel tried to access some bad page. We'll have to
- * terminate things with extreme prejudice.
- */
-
- bust_spinlocks(1);
-
- if (address < PAGE_SIZE)
- printk(KERN_ALERT "Unable to handle kernel NULL pointer dereference");
- else
- printk(KERN_ALERT "Unable to handle kernel paging request");
- printk(" at virtual address %08lx\n",address);
- printk(" printing eip:\n");
- printk("%08lx\n", regs->eip);
- page = ((unsigned long *) cur_pgd)[address >> 22];
- printk(KERN_ALERT "*pde=%08lx(%08lx)\n", page, machine_to_phys(page));
- if (page & 1) {
- page &= PAGE_MASK;
- address &= 0x003ff000;
- page = machine_to_phys(page);
- page = ((unsigned long *) __va(page))[address >> PAGE_SHIFT];
- printk(KERN_ALERT "*pte=%08lx(%08lx)\n", page,
- machine_to_phys(page));
- }
- die("Oops", regs, error_code);
- bust_spinlocks(0);
- do_exit(SIGKILL);
-
-/*
- * We ran out of memory, or some other thing happened to us that made
- * us unable to handle the page fault gracefully.
- */
-out_of_memory:
- if (tsk->pid == 1) {
- yield();
- goto survive;
- }
- up_read(&mm->mmap_sem);
- printk("VM: killing process %s\n", tsk->comm);
- if (error_code & 4)
- do_exit(SIGKILL);
- goto no_context;
-
-do_sigbus:
- up_read(&mm->mmap_sem);
-
- /*
- * Send a sigbus, regardless of whether we were in kernel
- * or user mode.
- */
- tsk->thread.cr2 = address;
- tsk->thread.error_code = error_code;
- tsk->thread.trap_no = 14;
- info.si_signo = SIGBUS;
- info.si_errno = 0;
- info.si_code = BUS_ADRERR;
- info.si_addr = (void *)address;
- force_sig_info(SIGBUS, &info, tsk);
-
- /* Kernel mode? Handle exceptions or die */
- if (!(error_code & 4))
- goto no_context;
- return;
-
-vmalloc_fault:
- {
- /*
- * Synchronize this task's top level page-table
- * with the 'reference' page table.
- *
- * Do _not_ use "tsk" here. We might be inside
- * an interrupt in the middle of a task switch..
- */
- int offset = __pgd_offset(address);
- pgd_t *pgd, *pgd_k;
- pmd_t *pmd, *pmd_k;
- pte_t *pte_k;
-
- pgd = offset + cur_pgd;
- pgd_k = init_mm.pgd + offset;
-
- if (!pgd_present(*pgd_k))
- goto no_context;
- set_pgd(pgd, *pgd_k);
-
- pmd = pmd_offset(pgd, address);
- pmd_k = pmd_offset(pgd_k, address);
- if (!pmd_present(*pmd_k))
- goto no_context;
- set_pmd(pmd, *pmd_k);
- XENO_flush_page_update_queue(); /* flush PMD update */
-
- pte_k = pte_offset(pmd_k, address);
- if (!pte_present(*pte_k))
- goto no_context;
- return;
- }
-}
+++ /dev/null
-
-#include <linux/slab.h>
-#include <linux/shm.h>
-#include <linux/mman.h>
-#include <linux/pagemap.h>
-#include <linux/swap.h>
-#include <linux/swapctl.h>
-#include <linux/smp_lock.h>
-#include <linux/init.h>
-#include <linux/file.h>
-#include <linux/fs.h>
-#include <linux/personality.h>
-
-#include <asm/uaccess.h>
-#include <asm/pgalloc.h>
-
-/*
-static int direct_mapped(unsigned long addr)
-{
- direct_mmap_node_t * node;
- struct list_head * curr;
- struct list_head * direct_list = ¤t->mm->context.direct_list;
-
- curr = direct_list->next;
- while(curr != direct_list){
- node = list_entry(curr, direct_mmap_node_t, list);
- if(node->addr == addr)
- break;
- curr = curr->next;
- }
-
- if(curr == direct_list)
- return 0;
-
- return 1;
-}
-*/
-/*
-unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr, unsigned long len, unsigned long pgoff, unsigned long flags)
-{
- struct vm_area_struct *vma;
-
- if (len > TASK_SIZE)
- return -ENOMEM;
-
- if (addr) {
- addr = PAGE_ALIGN(addr);
- vma = find_vma(current->mm, addr);
- if (TASK_SIZE - len >= addr &&
- (!vma || addr + len <= vma->vm_start))
- return addr;
- }
- addr = PAGE_ALIGN(TASK_UNMAPPED_BASE);
-
- for (vma = find_vma(current->mm, addr); ; vma = vma->vm_next) {
- if (TASK_SIZE - len < addr)
- return -ENOMEM;
-
- if ((!vma || addr + len <= vma->vm_start) && !direct_mapped(addr))
- return addr;
-
- addr = vma->vm_end;
- }
-}
-*/
-struct list_head *find_direct(struct list_head *list, unsigned long addr)
-{
- struct list_head * curr;
- struct list_head * direct_list = ¤t->mm->context.direct_list;
- direct_mmap_node_t * node;
-
- for ( curr = direct_list->next; curr != direct_list; curr = curr->next )
- {
- node = list_entry(curr, direct_mmap_node_t, list);
- if ( node->vm_start >= addr ) break;
- }
-
- return curr;
-}
-
-unsigned long arch_get_unmapped_area(struct file *filp, unsigned long
-addr, unsigned long len, unsigned long pgoff, unsigned long flags)
-{
- struct vm_area_struct *vma;
- direct_mmap_node_t * node;
- struct list_head * curr;
- struct list_head * direct_list = ¤t->mm->context.direct_list;
-
- if (len > TASK_SIZE)
- return -ENOMEM;
-
- if ( addr )
- {
- addr = PAGE_ALIGN(addr);
- vma = find_vma(current->mm, addr);
- curr = find_direct(direct_list, addr);
- node = list_entry(curr, direct_mmap_node_t, list);
- if ( (TASK_SIZE - len >= addr) &&
- (!vma || addr + len <= vma->vm_start) &&
- ((curr == direct_list) || addr + len <= node->vm_start) )
- return addr;
- }
-
- addr = PAGE_ALIGN(TASK_UNMAPPED_BASE);
-
-
- /* Find first VMA and direct_map nodes with vm_start > addr */
- vma = find_vma(current->mm, addr);
- curr = find_direct(direct_list, addr);
- node = list_entry(curr, direct_mmap_node_t, list);
-
- for ( ; ; )
- {
- if ( TASK_SIZE - len < addr ) return -ENOMEM;
-
- if ( vma && ((curr == direct_list) || (vma->vm_start < node->vm_start)))
- {
- /* Do we fit before VMA node? */
- if ( addr + len <= vma->vm_start ) return addr;
- addr = vma->vm_end;
- vma = vma->vm_next;
- }
- else if ( curr != direct_list )
- {
- /* Do we fit before direct_map node? */
- if ( addr + len <= node->vm_start) return addr;
- addr = node->vm_end;
- curr = curr->next;
- node = list_entry(curr, direct_mmap_node_t, list);
- }
- else
- {
- /* !vma && curr == direct_list */
- return addr;
- }
- }
-}
+++ /dev/null
-/******************************************************************************
- * xeno/mm/hypervisor.c
- *
- * Update page tables via the hypervisor.
- *
- * Copyright (c) 2002, K A Fraser
- */
-
-#include <linux/config.h>
-#include <linux/sched.h>
-#include <asm/hypervisor.h>
-#include <asm/page.h>
-#include <asm/pgtable.h>
-#include <asm/multicall.h>
-
-/*
- * This suffices to protect us if we ever move to SMP domains.
- * Further, it protects us against interrupts. At the very least, this is
- * required for the network driver which flushes the update queue before
- * pushing new receive buffers.
- */
-static spinlock_t update_lock = SPIN_LOCK_UNLOCKED;
-
-#define QUEUE_SIZE 2048
-static page_update_request_t update_queue[QUEUE_SIZE];
-unsigned int pt_update_queue_idx = 0;
-#define idx pt_update_queue_idx
-
-#if PT_UPDATE_DEBUG > 0
-page_update_debug_t update_debug_queue[QUEUE_SIZE] = {{0}};
-#undef queue_l1_entry_update
-#undef queue_l2_entry_update
-static void DEBUG_allow_pt_reads(void)
-{
- pte_t *pte;
- page_update_request_t update;
- int i;
- for ( i = idx-1; i >= 0; i-- )
- {
- pte = update_debug_queue[i].ptep;
- if ( pte == NULL ) continue;
- update_debug_queue[i].ptep = NULL;
- update.ptr = phys_to_machine(__pa(pte));
- update.val = update_debug_queue[i].pteval;
- HYPERVISOR_pt_update(&update, 1);
- }
-}
-static void DEBUG_disallow_pt_read(unsigned long pa)
-{
- pte_t *pte;
- pmd_t *pmd;
- pgd_t *pgd;
- unsigned long pteval;
- /*
- * We may fault because of an already outstanding update.
- * That's okay -- it'll get fixed up in the fault handler.
- */
- page_update_request_t update;
- unsigned long va = (unsigned long)__va(pa);
- pgd = pgd_offset_k(va);
- pmd = pmd_offset(pgd, va);
- pte = pte_offset(pmd, va);
- update.ptr = phys_to_machine(__pa(pte));
- pteval = *(unsigned long *)pte;
- update.val = pteval & ~_PAGE_PRESENT;
- HYPERVISOR_pt_update(&update, 1);
- update_debug_queue[idx].ptep = pte;
- update_debug_queue[idx].pteval = pteval;
-}
-#endif
-
-#if PT_UPDATE_DEBUG > 1
-#undef queue_pt_switch
-#undef queue_tlb_flush
-#undef queue_invlpg
-#undef queue_pgd_pin
-#undef queue_pgd_unpin
-#undef queue_pte_pin
-#undef queue_pte_unpin
-#endif
-
-
-/*
- * MULTICALL_flush_page_update_queue:
- * This is a version of the flush which queues as part of a multicall.
- */
-void MULTICALL_flush_page_update_queue(void)
-{
- unsigned long flags;
- spin_lock_irqsave(&update_lock, flags);
- if ( idx != 0 )
- {
-#if PT_UPDATE_DEBUG > 1
- printk("Flushing %d entries from pt update queue\n", idx);
-#endif
-#if PT_UPDATE_DEBUG > 0
- DEBUG_allow_pt_reads();
-#endif
- queue_multicall2(__HYPERVISOR_pt_update, update_queue, idx);
- idx = 0;
- }
- spin_unlock_irqrestore(&update_lock, flags);
-}
-
-static inline void __flush_page_update_queue(void)
-{
-#if PT_UPDATE_DEBUG > 1
- printk("Flushing %d entries from pt update queue\n", idx);
-#endif
-#if PT_UPDATE_DEBUG > 0
- DEBUG_allow_pt_reads();
-#endif
- HYPERVISOR_pt_update(update_queue, idx);
- idx = 0;
-}
-
-void _flush_page_update_queue(void)
-{
- unsigned long flags;
- spin_lock_irqsave(&update_lock, flags);
- if ( idx != 0 ) __flush_page_update_queue();
- spin_unlock_irqrestore(&update_lock, flags);
-}
-
-static inline void increment_index(void)
-{
- idx++;
- if ( unlikely(idx == QUEUE_SIZE) ) __flush_page_update_queue();
-}
-
-void queue_l1_entry_update(unsigned long ptr, unsigned long val)
-{
- unsigned long flags;
- spin_lock_irqsave(&update_lock, flags);
-#if PT_UPDATE_DEBUG > 0
- DEBUG_disallow_pt_read(ptr);
-#endif
- update_queue[idx].ptr = phys_to_machine(ptr);
- update_queue[idx].val = val;
- increment_index();
- spin_unlock_irqrestore(&update_lock, flags);
-}
-
-void queue_l2_entry_update(unsigned long ptr, unsigned long val)
-{
- unsigned long flags;
- spin_lock_irqsave(&update_lock, flags);
- update_queue[idx].ptr = phys_to_machine(ptr);
- update_queue[idx].val = val;
- increment_index();
- spin_unlock_irqrestore(&update_lock, flags);
-}
-
-void queue_pt_switch(unsigned long ptr)
-{
- unsigned long flags;
- spin_lock_irqsave(&update_lock, flags);
- update_queue[idx].ptr = phys_to_machine(ptr);
- update_queue[idx].ptr |= PGREQ_EXTENDED_COMMAND;
- update_queue[idx].val = PGEXT_NEW_BASEPTR;
- increment_index();
- spin_unlock_irqrestore(&update_lock, flags);
-}
-
-void queue_tlb_flush(void)
-{
- unsigned long flags;
- spin_lock_irqsave(&update_lock, flags);
- update_queue[idx].ptr = PGREQ_EXTENDED_COMMAND;
- update_queue[idx].val = PGEXT_TLB_FLUSH;
- increment_index();
- spin_unlock_irqrestore(&update_lock, flags);
-}
-
-void queue_invlpg(unsigned long ptr)
-{
- unsigned long flags;
- spin_lock_irqsave(&update_lock, flags);
- update_queue[idx].ptr = PGREQ_EXTENDED_COMMAND;
- update_queue[idx].val = ptr & PAGE_MASK;
- update_queue[idx].val |= PGEXT_INVLPG;
- increment_index();
- spin_unlock_irqrestore(&update_lock, flags);
-}
-
-void queue_pgd_pin(unsigned long ptr)
-{
- unsigned long flags;
- spin_lock_irqsave(&update_lock, flags);
- update_queue[idx].ptr = phys_to_machine(ptr);
- update_queue[idx].ptr |= PGREQ_EXTENDED_COMMAND;
- update_queue[idx].val = PGEXT_PIN_L2_TABLE;
- increment_index();
- spin_unlock_irqrestore(&update_lock, flags);
-}
-
-void queue_pgd_unpin(unsigned long ptr)
-{
- unsigned long flags;
- spin_lock_irqsave(&update_lock, flags);
- update_queue[idx].ptr = phys_to_machine(ptr);
- update_queue[idx].ptr |= PGREQ_EXTENDED_COMMAND;
- update_queue[idx].val = PGEXT_UNPIN_TABLE;
- increment_index();
- spin_unlock_irqrestore(&update_lock, flags);
-}
-
-void queue_pte_pin(unsigned long ptr)
-{
- unsigned long flags;
- spin_lock_irqsave(&update_lock, flags);
- update_queue[idx].ptr = phys_to_machine(ptr);
- update_queue[idx].ptr |= PGREQ_EXTENDED_COMMAND;
- update_queue[idx].val = PGEXT_PIN_L1_TABLE;
- increment_index();
- spin_unlock_irqrestore(&update_lock, flags);
-}
-
-void queue_pte_unpin(unsigned long ptr)
-{
- unsigned long flags;
- spin_lock_irqsave(&update_lock, flags);
- update_queue[idx].ptr = phys_to_machine(ptr);
- update_queue[idx].ptr |= PGREQ_EXTENDED_COMMAND;
- update_queue[idx].val = PGEXT_UNPIN_TABLE;
- increment_index();
- spin_unlock_irqrestore(&update_lock, flags);
-}
-
-void queue_set_ldt(unsigned long ptr, unsigned long len)
-{
- unsigned long flags;
- spin_lock_irqsave(&update_lock, flags);
- update_queue[idx].ptr = PGREQ_EXTENDED_COMMAND | ptr;
- update_queue[idx].val = PGEXT_SET_LDT | (len << PGEXT_CMD_SHIFT);
- increment_index();
- spin_unlock_irqrestore(&update_lock, flags);
-}
+++ /dev/null
-/*
- * linux/arch/i386/mm/init.c
- *
- * Copyright (C) 1995 Linus Torvalds
- *
- * Support of BIGMEM added by Gerhard Wichert, Siemens AG, July 1999
- */
-
-#include <linux/config.h>
-#include <linux/signal.h>
-#include <linux/sched.h>
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/string.h>
-#include <linux/types.h>
-#include <linux/ptrace.h>
-#include <linux/mman.h>
-#include <linux/mm.h>
-#include <linux/swap.h>
-#include <linux/smp.h>
-#include <linux/init.h>
-#ifdef CONFIG_BLK_DEV_INITRD
-#include <linux/blk.h>
-#endif
-#include <linux/highmem.h>
-#include <linux/pagemap.h>
-#include <linux/bootmem.h>
-#include <linux/slab.h>
-
-#include <asm/processor.h>
-#include <asm/system.h>
-#include <asm/uaccess.h>
-#include <asm/pgtable.h>
-#include <asm/pgalloc.h>
-#include <asm/dma.h>
-#include <asm/apic.h>
-#include <asm/tlb.h>
-
-mmu_gather_t mmu_gathers[NR_CPUS];
-unsigned long highstart_pfn, highend_pfn;
-static unsigned long totalram_pages;
-static unsigned long totalhigh_pages;
-
-int do_check_pgt_cache(int low, int high)
-{
- int freed = 0;
- if(pgtable_cache_size > high) {
- do {
- if (!QUICKLIST_EMPTY(pgd_quicklist)) {
- free_pgd_slow(get_pgd_fast());
- freed++;
- }
- if (!QUICKLIST_EMPTY(pte_quicklist)) {
- pte_free_slow(pte_alloc_one_fast(NULL, 0));
- freed++;
- }
- } while(pgtable_cache_size > low);
- }
- return freed;
-}
-
-void show_mem(void)
-{
- int i, total = 0, reserved = 0;
- int shared = 0, cached = 0;
- int highmem = 0;
-
- printk("Mem-info:\n");
- show_free_areas();
- printk("Free swap: %6dkB\n",nr_swap_pages<<(PAGE_SHIFT-10));
- i = max_mapnr;
- while (i-- > 0) {
- total++;
- if (PageHighMem(mem_map+i))
- highmem++;
- if (PageReserved(mem_map+i))
- reserved++;
- else if (PageSwapCache(mem_map+i))
- cached++;
- else if (page_count(mem_map+i))
- shared += page_count(mem_map+i) - 1;
- }
- printk("%d pages of RAM\n", total);
- printk("%d pages of HIGHMEM\n",highmem);
- printk("%d reserved pages\n",reserved);
- printk("%d pages shared\n",shared);
- printk("%d pages swap cached\n",cached);
- printk("%ld pages in page table cache\n",pgtable_cache_size);
- show_buffers();
-}
-
-/* References to section boundaries */
-
-extern char _text, _etext, _edata, __bss_start, _end;
-extern char __init_begin, __init_end;
-
-static inline void set_pte_phys (unsigned long vaddr,
- unsigned long phys, pgprot_t flags)
-{
- pgprot_t prot;
- pgd_t *pgd;
- pmd_t *pmd;
- pte_t *pte;
-
- pgd = init_mm.pgd + __pgd_offset(vaddr);
- if (pgd_none(*pgd)) {
- printk("PAE BUG #00!\n");
- return;
- }
- pmd = pmd_offset(pgd, vaddr);
- if (pmd_none(*pmd)) {
- printk("PAE BUG #01!\n");
- return;
- }
- pte = pte_offset(pmd, vaddr);
-#if 0 // XXX Xen ?????
- /* <phys,flags> stored as-is, to permit clearing entries */
- set_pte(pte, mk_pte_phys(phys, flags));
-#endif
- if (pte_val(*pte))
- pte_ERROR(*pte);
-
- pgprot_val(prot) = pgprot_val(PAGE_KERNEL) | pgprot_val(flags);
-
- /* We queue directly, avoiding hidden phys->machine translation. */
- queue_l1_entry_update(__pa(pte), phys | pgprot_val(prot));
-
- /*
- * It's enough to flush this one mapping.
- * (PGE mappings get flushed as well)
- */
- __flush_tlb_one(vaddr);
-}
-
-void __set_fixmap (enum fixed_addresses idx, unsigned long phys,
- pgprot_t flags)
-{
- unsigned long address = __fix_to_virt(idx);
-
- if (idx >= __end_of_fixed_addresses) {
- printk("Invalid __set_fixmap\n");
- return;
- }
- set_pte_phys(address, phys, flags);
-}
-
-static void __init fixrange_init (unsigned long start,
- unsigned long end, pgd_t *pgd_base)
-{
- pgd_t *pgd, *kpgd;
- pmd_t *pmd, *kpmd;
- pte_t *pte, *kpte;
- int i, j;
- unsigned long vaddr;
-
- vaddr = start;
- i = __pgd_offset(vaddr);
- j = __pmd_offset(vaddr);
- pgd = pgd_base + i;
-
- for ( ; (i < PTRS_PER_PGD) && (vaddr != end); pgd++, i++) {
-#if CONFIG_X86_PAE
- if (pgd_none(*pgd)) {
- pmd = (pmd_t *) alloc_bootmem_low_pages(PAGE_SIZE);
- set_pgd(pgd, __pgd(__pa(pmd) + 0x1));
- if (pmd != pmd_offset(pgd, 0))
- printk("PAE BUG #02!\n");
- }
- pmd = pmd_offset(pgd, vaddr);
-#else
- pmd = (pmd_t *)pgd;
-#endif
- for (; (j < PTRS_PER_PMD) && (vaddr != end); pmd++, j++) {
- if (pmd_none(*pmd)) {
- pte = (pte_t *) alloc_bootmem_low_pages(PAGE_SIZE);
- clear_page(pte);
- kpgd = pgd_offset_k((unsigned long)pte);
- kpmd = pmd_offset(kpgd, (unsigned long)pte);
- kpte = pte_offset(kpmd, (unsigned long)pte);
- queue_l1_entry_update(__pa(kpte),
- (*(unsigned long *)kpte)&~_PAGE_RW);
-
- set_pmd(pmd, __pmd(_KERNPG_TABLE + __pa(pte)));
-
- // XXX Xen below reqd ?
- //if (pte != pte_offset(pmd, 0))
- // BUG();
- }
- vaddr += PMD_SIZE;
- }
- j = 0;
- }
-
- XENO_flush_page_update_queue();
-}
-
-
-static void __init zone_sizes_init(void)
-{
- unsigned long zones_size[MAX_NR_ZONES] = {0, 0, 0};
- unsigned int max_dma, high, low;
-
- max_dma = virt_to_phys((char *)MAX_DMA_ADDRESS) >> PAGE_SHIFT;
- low = max_low_pfn;
- high = highend_pfn;
-
- if (low < max_dma)
- zones_size[ZONE_DMA] = low;
- else {
- zones_size[ZONE_DMA] = max_dma;
- zones_size[ZONE_NORMAL] = low - max_dma;
-#ifdef CONFIG_HIGHMEM
- zones_size[ZONE_HIGHMEM] = high - low;
-#endif
- }
- free_area_init(zones_size);
-}
-
-/*
- * paging_init() sets up the page tables - note that the first 8MB are
- * already mapped by head.S.
- *
- * This routines also unmaps the page at virtual kernel address 0, so
- * that we can trap those pesky NULL-reference errors in the kernel.
- */
-void __init paging_init(void)
-{
- unsigned long vaddr;
-
- zone_sizes_init();
-
- /*
- * Fixed mappings, only the page table structure has to be created -
- * mappings will be set by set_fixmap():
- */
- vaddr = __fix_to_virt(__end_of_fixed_addresses - 1) & PMD_MASK;
- fixrange_init(vaddr, HYPERVISOR_VIRT_START, init_mm.pgd);
-
- /* Cheesy: this can probably be moved to the blkdev driver. */
- set_fixmap(FIX_BLKRING_BASE, start_info.blk_ring);
-
-#ifdef CONFIG_HIGHMEM
-#error
- kmap_init();
-#endif
-}
-
-static inline int page_is_ram (unsigned long pagenr)
-{
- return 1;
-}
-
-#ifdef CONFIG_HIGHMEM
-void __init one_highpage_init(struct page *page, int pfn, int bad_ppro)
-{
- if (!page_is_ram(pfn)) {
- SetPageReserved(page);
- return;
- }
-
- if (bad_ppro && page_kills_ppro(pfn)) {
- SetPageReserved(page);
- return;
- }
-
- ClearPageReserved(page);
- set_bit(PG_highmem, &page->flags);
- atomic_set(&page->count, 1);
- __free_page(page);
- totalhigh_pages++;
-}
-#endif /* CONFIG_HIGHMEM */
-
-static void __init set_max_mapnr_init(void)
-{
-#ifdef CONFIG_HIGHMEM
- highmem_start_page = mem_map + highstart_pfn;
- max_mapnr = num_physpages = highend_pfn;
- num_mappedpages = max_low_pfn;
-#else
- max_mapnr = num_mappedpages = num_physpages = max_low_pfn;
-#endif
-}
-
-static int __init free_pages_init(void)
-{
- int bad_ppro, reservedpages, pfn;
-
- /* this will put all low memory onto the freelists */
- totalram_pages += free_all_bootmem();
-
- reservedpages = 0;
- for (pfn = 0; pfn < max_low_pfn; pfn++) {
- /*
- * Only count reserved RAM pages
- */
- if (page_is_ram(pfn) && PageReserved(mem_map+pfn))
- reservedpages++;
- }
-#ifdef CONFIG_HIGHMEM
- for (pfn = highend_pfn-1; pfn >= highstart_pfn; pfn--)
- one_highpage_init((struct page *) (mem_map + pfn), pfn, bad_ppro);
- totalram_pages += totalhigh_pages;
-#endif
- return reservedpages;
-}
-
-void __init mem_init(void)
-{
- int codesize, reservedpages, datasize, initsize;
-
- if (!mem_map)
- BUG();
-
- set_max_mapnr_init();
-
- high_memory = (void *) __va(max_low_pfn * PAGE_SIZE);
-
- /* clear the zero-page */
- memset(empty_zero_page, 0, PAGE_SIZE);
-
- reservedpages = free_pages_init();
-
- codesize = (unsigned long) &_etext - (unsigned long) &_text;
- datasize = (unsigned long) &_edata - (unsigned long) &_etext;
- initsize = (unsigned long) &__init_end - (unsigned long) &__init_begin;
-
- printk(KERN_INFO "Memory: %luk/%luk available (%dk kernel code, %dk reserved, %dk data, %dk init, %ldk highmem)\n",
- (unsigned long) nr_free_pages() << (PAGE_SHIFT-10),
- max_mapnr << (PAGE_SHIFT-10),
- codesize >> 10,
- reservedpages << (PAGE_SHIFT-10),
- datasize >> 10,
- initsize >> 10,
- (unsigned long) (totalhigh_pages << (PAGE_SHIFT-10))
- );
-
- boot_cpu_data.wp_works_ok = 1;
-}
-
-void free_initmem(void)
-{
- unsigned long addr;
-
- addr = (unsigned long)(&__init_begin);
- for (; addr < (unsigned long)(&__init_end); addr += PAGE_SIZE) {
- ClearPageReserved(virt_to_page(addr));
- set_page_count(virt_to_page(addr), 1);
- free_page(addr);
- totalram_pages++;
- }
- printk (KERN_INFO "Freeing unused kernel memory: %dk freed\n", (&__init_end - &__init_begin) >> 10);
-}
-
-#ifdef CONFIG_BLK_DEV_INITRD
-void free_initrd_mem(unsigned long start, unsigned long end)
-{
- if (start < end)
- printk (KERN_INFO "Freeing initrd memory: %ldk freed\n", (end - start) >> 10);
- for (; start < end; start += PAGE_SIZE) {
- ClearPageReserved(virt_to_page(start));
- set_page_count(virt_to_page(start), 1);
- free_page(start);
- totalram_pages++;
- }
-}
-#endif
-
-void si_meminfo(struct sysinfo *val)
-{
- val->totalram = totalram_pages;
- val->sharedram = 0;
- val->freeram = nr_free_pages();
- val->bufferram = atomic_read(&buffermem_pages);
- val->totalhigh = totalhigh_pages;
- val->freehigh = nr_free_highpages();
- val->mem_unit = PAGE_SIZE;
- return;
-}
-
-#if defined(CONFIG_X86_PAE)
-struct kmem_cache_s *pae_pgd_cachep;
-void __init pgtable_cache_init(void)
-{
- /*
- * PAE pgds must be 16-byte aligned:
- */
- pae_pgd_cachep = kmem_cache_create("pae_pgd", 32, 0,
- SLAB_HWCACHE_ALIGN | SLAB_MUST_HWCACHE_ALIGN, NULL, NULL);
- if (!pae_pgd_cachep)
- panic("init_pae(): Cannot alloc pae_pgd SLAB cache");
-}
-#endif /* CONFIG_X86_PAE */
+++ /dev/null
-
-#include <linux/slab.h>
-#include <linux/list.h>
-
-int init_new_context(struct task_struct *tsk, struct mm_struct *mm)
-{
- INIT_LIST_HEAD(&mm->context.direct_list);
- return 0;
-}
-
-/* just free all elements of list identifying directly mapped areas */
-void destroy_context(struct mm_struct *mm)
-{
- direct_mmap_node_t * node;
- struct list_head * curr;
- struct list_head * direct_list = &mm->context.direct_list;
-
- curr = direct_list->next;
- while(curr != direct_list){
- node = list_entry(curr, direct_mmap_node_t, list);
- curr = curr->next;
- list_del(&node->list);
- kfree(node);
- }
-
-}
+++ /dev/null
-/* ld script to make i386 Linux kernel
- * Written by Martin Mares <mj@atrey.karlin.mff.cuni.cz>;
- */
-OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386")
-OUTPUT_ARCH(i386)
-ENTRY(_start)
-SECTIONS
-{
- . = 0xC0000000 + 0x000000;
- _text = .; /* Text and read-only data */
- .text : {
- *(.text)
- *(.fixup)
- *(.gnu.warning)
- } = 0x9090
-
- _etext = .; /* End of text section */
-
- .rodata : { *(.rodata) *(.rodata.*) }
- .kstrtab : { *(.kstrtab) }
-
- . = ALIGN(16); /* Exception table */
- __start___ex_table = .;
- __ex_table : { *(__ex_table) }
- __stop___ex_table = .;
-
- __start___ksymtab = .; /* Kernel symbol table */
- __ksymtab : { *(__ksymtab) }
- __stop___ksymtab = .;
-
- .data : { /* Data */
- *(.data)
- CONSTRUCTORS
- }
-
- _edata = .; /* End of data section */
-
- . = ALIGN(8192); /* init_task */
- .data.init_task : { *(.data.init_task) }
-
- . = ALIGN(4096); /* Init code and data */
- __init_begin = .;
- .text.init : { *(.text.init) }
- .data.init : { *(.data.init) }
- . = ALIGN(16);
- __setup_start = .;
- .setup.init : { *(.setup.init) }
- __setup_end = .;
- __initcall_start = .;
- .initcall.init : { *(.initcall.init) }
- __initcall_end = .;
- . = ALIGN(4096);
- __init_end = .;
-
- . = ALIGN(4096);
- .data.page_aligned : { *(.data.idt) }
-
- . = ALIGN(32);
- .data.cacheline_aligned : { *(.data.cacheline_aligned) }
-
- __bss_start = .; /* BSS */
- .bss : {
- *(.bss)
- }
- _end = . ;
-
- /* Sections to be discarded */
- /DISCARD/ : {
- *(.text.exit)
- *(.data.exit)
- *(.exitcall.exit)
- }
-
- /* Stabs debugging sections. */
- .stab 0 : { *(.stab) }
- .stabstr 0 : { *(.stabstr) }
- .stab.excl 0 : { *(.stab.excl) }
- .stab.exclstr 0 : { *(.stab.exclstr) }
- .stab.index 0 : { *(.stab.index) }
- .stab.indexstr 0 : { *(.stab.indexstr) }
- .comment 0 : { *(.comment) }
-}
+++ /dev/null
-/*
- * Code extracted from
- * linux/kernel/hd.c
- *
- * Copyright (C) 1991-1998 Linus Torvalds
- *
- * devfs support - jj, rgooch, 980122
- *
- * Moved partition checking code to fs/partitions* - Russell King
- * (linux@arm.uk.linux.org)
- */
-
-/*
- * TODO: rip out the remaining init crap from this file --hch
- */
-
-#include <linux/config.h>
-#include <linux/module.h>
-#include <linux/fs.h>
-#include <linux/genhd.h>
-#include <linux/kernel.h>
-#include <linux/blk.h>
-#include <linux/init.h>
-#include <linux/spinlock.h>
-#include <linux/seq_file.h>
-
-
-/*
- * Global kernel list of partitioning information.
- *
- * XXX: you should _never_ access this directly.
- * the only reason this is exported is source compatiblity.
- */
-/*static*/ struct gendisk *gendisk_head;
-static struct gendisk *gendisk_array[MAX_BLKDEV];
-static rwlock_t gendisk_lock = RW_LOCK_UNLOCKED;
-
-EXPORT_SYMBOL(gendisk_head);
-
-
-/**
- * add_gendisk - add partitioning information to kernel list
- * @gp: per-device partitioning information
- *
- * This function registers the partitioning information in @gp
- * with the kernel.
- */
-void
-add_gendisk(struct gendisk *gp)
-{
- struct gendisk *sgp;
-
- write_lock(&gendisk_lock);
-
- /*
- * In 2.5 this will go away. Fix the drivers who rely on
- * old behaviour.
- */
-
- for (sgp = gendisk_head; sgp; sgp = sgp->next)
- {
- if (sgp == gp)
- {
-// printk(KERN_ERR "add_gendisk: device major %d is buggy and added a live gendisk!\n",
-// sgp->major)
- goto out;
- }
- }
- gendisk_array[gp->major] = gp;
- gp->next = gendisk_head;
- gendisk_head = gp;
-out:
- write_unlock(&gendisk_lock);
-}
-
-EXPORT_SYMBOL(add_gendisk);
-
-
-/**
- * del_gendisk - remove partitioning information from kernel list
- * @gp: per-device partitioning information
- *
- * This function unregisters the partitioning information in @gp
- * with the kernel.
- */
-void
-del_gendisk(struct gendisk *gp)
-{
- struct gendisk **gpp;
-
- write_lock(&gendisk_lock);
- gendisk_array[gp->major] = NULL;
- for (gpp = &gendisk_head; *gpp; gpp = &((*gpp)->next))
- if (*gpp == gp)
- break;
- if (*gpp)
- *gpp = (*gpp)->next;
- write_unlock(&gendisk_lock);
-}
-
-EXPORT_SYMBOL(del_gendisk);
-
-
-/**
- * get_gendisk - get partitioning information for a given device
- * @dev: device to get partitioning information for
- *
- * This function gets the structure containing partitioning
- * information for the given device @dev.
- */
-struct gendisk *
-get_gendisk(kdev_t dev)
-{
- struct gendisk *gp = NULL;
- int maj = MAJOR(dev);
-
- read_lock(&gendisk_lock);
- if ((gp = gendisk_array[maj]))
- goto out;
-
- /* This is needed for early 2.4 source compatiblity. --hch */
- for (gp = gendisk_head; gp; gp = gp->next)
- if (gp->major == maj)
- break;
-out:
- read_unlock(&gendisk_lock);
- return gp;
-}
-
-EXPORT_SYMBOL(get_gendisk);
-
-
-/**
- * walk_gendisk - issue a command for every registered gendisk
- * @walk: user-specified callback
- * @data: opaque data for the callback
- *
- * This function walks through the gendisk chain and calls back
- * into @walk for every element.
- */
-int
-walk_gendisk(int (*walk)(struct gendisk *, void *), void *data)
-{
- struct gendisk *gp;
- int error = 0;
-
- read_lock(&gendisk_lock);
- for (gp = gendisk_head; gp; gp = gp->next)
- if ((error = walk(gp, data)))
- break;
- read_unlock(&gendisk_lock);
-
- return error;
-}
-
-#ifdef CONFIG_PROC_FS
-/* iterator */
-static void *part_start(struct seq_file *s, loff_t *ppos)
-{
- struct gendisk *gp;
- loff_t pos = *ppos;
-
- read_lock(&gendisk_lock);
- for (gp = gendisk_head; gp; gp = gp->next)
- if (!pos--)
- return gp;
- return NULL;
-}
-
-static void *part_next(struct seq_file *s, void *v, loff_t *pos)
-{
- ++*pos;
- return ((struct gendisk *)v)->next;
-}
-
-static void part_stop(struct seq_file *s, void *v)
-{
- read_unlock(&gendisk_lock);
-}
-
-static int part_show(struct seq_file *s, void *v)
-{
- struct gendisk *gp = v;
- char buf[64];
- int n;
-
- if (gp == gendisk_head) {
- seq_puts(s, "major minor #blocks start_sect nr_sects name"
-#ifdef CONFIG_BLK_STATS
- " rio rmerge rsect ruse wio wmerge "
- "wsect wuse running use aveq"
-#endif
- "\n\n");
- }
-
- /* show the full disk and all non-0 size partitions of it */
- for (n = 0; n < (gp->nr_real << gp->minor_shift); n++) {
- if (gp->part[n].nr_sects) {
-#ifdef CONFIG_BLK_STATS
- struct hd_struct *hd = &gp->part[n];
-
- disk_round_stats(hd);
- seq_printf(s, "%4d %4d %10d %10ld %s "
- "%d %d %d %d %d %d %d %d %d %d %d\n",
- gp->major, n, gp->sizes[n],
- gp->part[n].start_sect,
- gp->part[n].nr_sects,
- disk_name(gp, n, buf),
- hd->rd_ios, hd->rd_merges,
-#define MSEC(x) ((x) * 1000 / HZ)
- hd->rd_sectors, MSEC(hd->rd_ticks),
- hd->wr_ios, hd->wr_merges,
- hd->wr_sectors, MSEC(hd->wr_ticks),
- hd->ios_in_flight, MSEC(hd->io_ticks),
- MSEC(hd->aveq));
-#else
- seq_printf(s, "%4d %4d %10d %10ld %10ld %s\n",
- gp->major, n, gp->sizes[n],
- gp->part[n].start_sect,
- gp->part[n].nr_sects,
- disk_name(gp, n, buf));
-#endif /* CONFIG_BLK_STATS */
- }
- }
-
- return 0;
-}
-
-struct seq_operations partitions_op = {
- .start = part_start,
- .next = part_next,
- .stop = part_stop,
- .show = part_show,
-};
-#endif
-
-extern int blk_dev_init(void);
-extern int net_dev_init(void);
-extern void console_map_init(void);
-extern int atmdev_init(void);
-
-int __init device_init(void)
-{
- blk_dev_init();
- sti();
-#ifdef CONFIG_NET
- net_dev_init();
-#endif
-#ifdef CONFIG_ATM
- (void) atmdev_init();
-#endif
-#ifdef CONFIG_VT
- console_map_init();
-#endif
- return 0;
-}
-
-__initcall(device_init);
+++ /dev/null
-/*
- * linux/drivers/block/ll_rw_blk.c
- *
- * Copyright (C) 1991, 1992 Linus Torvalds
- * Copyright (C) 1994, Karl Keyte: Added support for disk statistics
- * Elevator latency, (C) 2000 Andrea Arcangeli <andrea@suse.de> SuSE
- * Queue request tables / lock, selectable elevator, Jens Axboe <axboe@suse.de>
- * kernel-doc documentation started by NeilBrown <neilb@cse.unsw.edu.au> - July2000
- */
-
-/*
- * This handles all read/write requests to block devices
- */
-#include <linux/sched.h>
-#include <linux/kernel.h>
-#include <linux/kernel_stat.h>
-#include <linux/errno.h>
-#include <linux/string.h>
-#include <linux/config.h>
-#include <linux/locks.h>
-#include <linux/mm.h>
-#include <linux/swap.h>
-#include <linux/init.h>
-#include <linux/smp_lock.h>
-#include <linux/completion.h>
-#include <linux/bootmem.h>
-
-#include <asm/system.h>
-#include <asm/io.h>
-#include <linux/blk.h>
-#include <linux/highmem.h>
-#include <linux/slab.h>
-#include <linux/module.h>
-
-/*
- * MAC Floppy IWM hooks
- */
-
-#ifdef CONFIG_MAC_FLOPPY_IWM
-extern int mac_floppy_init(void);
-#endif
-
-/*
- * For the allocated request tables
- */
-static kmem_cache_t *request_cachep;
-
-/*
- * The "disk" task queue is used to start the actual requests
- * after a plug
- */
-DECLARE_TASK_QUEUE(tq_disk);
-
-/*
- * Protect the request list against multiple users..
- *
- * With this spinlock the Linux block IO subsystem is 100% SMP threaded
- * from the IRQ event side, and almost 100% SMP threaded from the syscall
- * side (we still have protect against block device array operations, and
- * the do_request() side is casually still unsafe. The kernel lock protects
- * this part currently.).
- *
- * there is a fair chance that things will work just OK if these functions
- * are called with no global kernel lock held ...
- */
-spinlock_t io_request_lock = SPIN_LOCK_UNLOCKED;
-
-/* This specifies how many sectors to read ahead on the disk. */
-
-int read_ahead[MAX_BLKDEV];
-
-/* blk_dev_struct is:
- * *request_fn
- * *current_request
- */
-struct blk_dev_struct blk_dev[MAX_BLKDEV]; /* initialized by blk_dev_init() */
-
-/*
- * blk_size contains the size of all block-devices in units of 1024 byte
- * sectors:
- *
- * blk_size[MAJOR][MINOR]
- *
- * if (!blk_size[MAJOR]) then no minor size checking is done.
- */
-int * blk_size[MAX_BLKDEV];
-
-/*
- * blksize_size contains the size of all block-devices:
- *
- * blksize_size[MAJOR][MINOR]
- *
- * if (!blksize_size[MAJOR]) then 1024 bytes is assumed.
- */
-int * blksize_size[MAX_BLKDEV];
-
-/*
- * hardsect_size contains the size of the hardware sector of a device.
- *
- * hardsect_size[MAJOR][MINOR]
- *
- * if (!hardsect_size[MAJOR])
- * then 512 bytes is assumed.
- * else
- * sector_size is hardsect_size[MAJOR][MINOR]
- * This is currently set by some scsi devices and read by the msdos fs driver.
- * Other uses may appear later.
- */
-int * hardsect_size[MAX_BLKDEV];
-
-/*
- * The following tunes the read-ahead algorithm in mm/filemap.c
- */
-int * max_readahead[MAX_BLKDEV];
-
-/*
- * Max number of sectors per request
- */
-int * max_sectors[MAX_BLKDEV];
-
-unsigned long blk_max_low_pfn, blk_max_pfn;
-int blk_nohighio = 0;
-
-static inline int get_max_sectors(kdev_t dev)
-{
- if (!max_sectors[MAJOR(dev)])
- return MAX_SECTORS;
- return max_sectors[MAJOR(dev)][MINOR(dev)];
-}
-
-inline request_queue_t *blk_get_queue(kdev_t dev)
-{
- struct blk_dev_struct *bdev = blk_dev + MAJOR(dev);
-
- if (bdev->queue)
- return bdev->queue(dev);
- else
- return &blk_dev[MAJOR(dev)].request_queue;
-}
-
-static int __blk_cleanup_queue(struct request_list *list)
-{
- struct list_head *head = &list->free;
- struct request *rq;
- int i = 0;
-
- while (!list_empty(head)) {
- rq = list_entry(head->next, struct request, queue);
- list_del(&rq->queue);
- kmem_cache_free(request_cachep, rq);
- i++;
- };
-
- if (i != list->count)
- printk("request list leak!\n");
-
- list->count = 0;
- return i;
-}
-
-/**
- * blk_cleanup_queue: - release a &request_queue_t when it is no longer needed
- * @q: the request queue to be released
- *
- * Description:
- * blk_cleanup_queue is the pair to blk_init_queue(). It should
- * be called when a request queue is being released; typically
- * when a block device is being de-registered. Currently, its
- * primary task it to free all the &struct request structures that
- * were allocated to the queue.
- * Caveat:
- * Hopefully the low level driver will have finished any
- * outstanding requests first...
- **/
-void blk_cleanup_queue(request_queue_t * q)
-{
- int count = q->nr_requests;
-
- count -= __blk_cleanup_queue(&q->rq[READ]);
- count -= __blk_cleanup_queue(&q->rq[WRITE]);
-
- if (count)
- printk("blk_cleanup_queue: leaked requests (%d)\n", count);
-
- memset(q, 0, sizeof(*q));
-}
-
-/**
- * blk_queue_headactive - indicate whether head of request queue may be active
- * @q: The queue which this applies to.
- * @active: A flag indication where the head of the queue is active.
- *
- * Description:
- * The driver for a block device may choose to leave the currently active
- * request on the request queue, removing it only when it has completed.
- * The queue handling routines assume this by default for safety reasons
- * and will not involve the head of the request queue in any merging or
- * reordering of requests when the queue is unplugged (and thus may be
- * working on this particular request).
- *
- * If a driver removes requests from the queue before processing them, then
- * it may indicate that it does so, there by allowing the head of the queue
- * to be involved in merging and reordering. This is done be calling
- * blk_queue_headactive() with an @active flag of %0.
- *
- * If a driver processes several requests at once, it must remove them (or
- * at least all but one of them) from the request queue.
- *
- * When a queue is plugged the head will be assumed to be inactive.
- **/
-
-void blk_queue_headactive(request_queue_t * q, int active)
-{
- q->head_active = active;
-}
-
-/**
- * blk_queue_make_request - define an alternate make_request function for a device
- * @q: the request queue for the device to be affected
- * @mfn: the alternate make_request function
- *
- * Description:
- * The normal way for &struct buffer_heads to be passed to a device
- * driver is for them to be collected into requests on a request
- * queue, and then to allow the device driver to select requests
- * off that queue when it is ready. This works well for many block
- * devices. However some block devices (typically virtual devices
- * such as md or lvm) do not benefit from the processing on the
- * request queue, and are served best by having the requests passed
- * directly to them. This can be achieved by providing a function
- * to blk_queue_make_request().
- *
- * Caveat:
- * The driver that does this *must* be able to deal appropriately
- * with buffers in "highmemory", either by calling bh_kmap() to get
- * a kernel mapping, to by calling create_bounce() to create a
- * buffer in normal memory.
- **/
-
-void blk_queue_make_request(request_queue_t * q, make_request_fn * mfn)
-{
- q->make_request_fn = mfn;
-}
-
-/**
- * blk_queue_bounce_limit - set bounce buffer limit for queue
- * @q: the request queue for the device
- * @dma_addr: bus address limit
- *
- * Description:
- * Different hardware can have different requirements as to what pages
- * it can do I/O directly to. A low level driver can call
- * blk_queue_bounce_limit to have lower memory pages allocated as bounce
- * buffers for doing I/O to pages residing above @page. By default
- * the block layer sets this to the highest numbered "low" memory page.
- **/
-void blk_queue_bounce_limit(request_queue_t *q, u64 dma_addr)
-{
- unsigned long bounce_pfn = dma_addr >> PAGE_SHIFT;
- unsigned long mb = dma_addr >> 20;
- static request_queue_t *old_q;
-
- /*
- * keep this for debugging for now...
- */
- if (dma_addr != BLK_BOUNCE_HIGH && q != old_q) {
- old_q = q;
- printk("blk: queue %p, ", q);
- if (dma_addr == BLK_BOUNCE_ANY)
- printk("no I/O memory limit\n");
- else
- printk("I/O limit %luMb (mask 0x%Lx)\n", mb,
- (long long) dma_addr);
- }
-
- q->bounce_pfn = bounce_pfn;
-}
-
-
-/*
- * can we merge the two segments, or do we need to start a new one?
- */
-inline int blk_seg_merge_ok(struct buffer_head *bh, struct buffer_head *nxt)
-{
- /*
- * if bh and nxt are contigous and don't cross a 4g boundary, it's ok
- */
- if (BH_CONTIG(bh, nxt) && BH_PHYS_4G(bh, nxt))
- return 1;
-
- return 0;
-}
-
-static inline int ll_new_segment(request_queue_t *q, struct request *req, int max_segments)
-{
- if (req->nr_segments < max_segments) {
- req->nr_segments++;
- return 1;
- }
- return 0;
-}
-
-static int ll_back_merge_fn(request_queue_t *q, struct request *req,
- struct buffer_head *bh, int max_segments)
-{
- if (blk_seg_merge_ok(req->bhtail, bh))
- return 1;
-
- return ll_new_segment(q, req, max_segments);
-}
-
-static int ll_front_merge_fn(request_queue_t *q, struct request *req,
- struct buffer_head *bh, int max_segments)
-{
- if (blk_seg_merge_ok(bh, req->bh))
- return 1;
-
- return ll_new_segment(q, req, max_segments);
-}
-
-static int ll_merge_requests_fn(request_queue_t *q, struct request *req,
- struct request *next, int max_segments)
-{
- int total_segments = req->nr_segments + next->nr_segments;
-
- if (blk_seg_merge_ok(req->bhtail, next->bh))
- total_segments--;
-
- if (total_segments > max_segments)
- return 0;
-
- req->nr_segments = total_segments;
- return 1;
-}
-
-/*
- * "plug" the device if there are no outstanding requests: this will
- * force the transfer to start only after we have put all the requests
- * on the list.
- *
- * This is called with interrupts off and no requests on the queue.
- * (and with the request spinlock acquired)
- */
-static void generic_plug_device(request_queue_t *q, kdev_t dev)
-{
- /*
- * no need to replug device
- */
- if (!list_empty(&q->queue_head) || q->plugged)
- return;
-
- q->plugged = 1;
- queue_task(&q->plug_tq, &tq_disk);
-}
-
-/*
- * remove the plug and let it rip..
- */
-static inline void __generic_unplug_device(request_queue_t *q)
-{
- if (q->plugged) {
- q->plugged = 0;
- if (!list_empty(&q->queue_head))
- q->request_fn(q);
- }
-}
-
-void generic_unplug_device(void *data)
-{
- request_queue_t *q = (request_queue_t *) data;
- unsigned long flags;
-
- spin_lock_irqsave(&io_request_lock, flags);
- __generic_unplug_device(q);
- spin_unlock_irqrestore(&io_request_lock, flags);
-}
-
-/** blk_grow_request_list
- * @q: The &request_queue_t
- * @nr_requests: how many requests are desired
- *
- * More free requests are added to the queue's free lists, bringing
- * the total number of requests to @nr_requests.
- *
- * The requests are added equally to the request queue's read
- * and write freelists.
- *
- * This function can sleep.
- *
- * Returns the (new) number of requests which the queue has available.
- */
-int blk_grow_request_list(request_queue_t *q, int nr_requests)
-{
- unsigned long flags;
- /* Several broken drivers assume that this function doesn't sleep,
- * this causes system hangs during boot.
- * As a temporary fix, make the function non-blocking.
- */
- spin_lock_irqsave(&io_request_lock, flags);
- while (q->nr_requests < nr_requests) {
- struct request *rq;
- int rw;
-
- rq = kmem_cache_alloc(request_cachep, SLAB_ATOMIC);
- if (rq == NULL)
- break;
- memset(rq, 0, sizeof(*rq));
- rq->rq_status = RQ_INACTIVE;
- rw = q->nr_requests & 1;
- list_add(&rq->queue, &q->rq[rw].free);
- q->rq[rw].count++;
- q->nr_requests++;
- }
- q->batch_requests = q->nr_requests / 4;
- if (q->batch_requests > 32)
- q->batch_requests = 32;
- spin_unlock_irqrestore(&io_request_lock, flags);
- return q->nr_requests;
-}
-
-static void blk_init_free_list(request_queue_t *q)
-{
- struct sysinfo si;
- int megs; /* Total memory, in megabytes */
- int nr_requests;
-
- INIT_LIST_HEAD(&q->rq[READ].free);
- INIT_LIST_HEAD(&q->rq[WRITE].free);
- q->rq[READ].count = 0;
- q->rq[WRITE].count = 0;
- q->nr_requests = 0;
-
- si_meminfo(&si);
- megs = si.totalram >> (20 - PAGE_SHIFT);
- nr_requests = 128;
- if (megs < 32)
- nr_requests /= 2;
- blk_grow_request_list(q, nr_requests);
-
- init_waitqueue_head(&q->wait_for_requests[0]);
- init_waitqueue_head(&q->wait_for_requests[1]);
- spin_lock_init(&q->queue_lock);
-}
-
-static int __make_request(request_queue_t * q, int rw, struct buffer_head * bh);
-
-/**
- * blk_init_queue - prepare a request queue for use with a block device
- * @q: The &request_queue_t to be initialised
- * @rfn: The function to be called to process requests that have been
- * placed on the queue.
- *
- * Description:
- * If a block device wishes to use the standard request handling procedures,
- * which sorts requests and coalesces adjacent requests, then it must
- * call blk_init_queue(). The function @rfn will be called when there
- * are requests on the queue that need to be processed. If the device
- * supports plugging, then @rfn may not be called immediately when requests
- * are available on the queue, but may be called at some time later instead.
- * Plugged queues are generally unplugged when a buffer belonging to one
- * of the requests on the queue is needed, or due to memory pressure.
- *
- * @rfn is not required, or even expected, to remove all requests off the
- * queue, but only as many as it can handle at a time. If it does leave
- * requests on the queue, it is responsible for arranging that the requests
- * get dealt with eventually.
- *
- * A global spin lock $io_request_lock must be held while manipulating the
- * requests on the request queue.
- *
- * The request on the head of the queue is by default assumed to be
- * potentially active, and it is not considered for re-ordering or merging
- * whenever the given queue is unplugged. This behaviour can be changed with
- * blk_queue_headactive().
- *
- * Note:
- * blk_init_queue() must be paired with a blk_cleanup_queue() call
- * when the block device is deactivated (such as at module unload).
- **/
-void blk_init_queue(request_queue_t * q, request_fn_proc * rfn)
-{
- INIT_LIST_HEAD(&q->queue_head);
- elevator_init(&q->elevator, ELEVATOR_LINUS);
- blk_init_free_list(q);
- q->request_fn = rfn;
- q->back_merge_fn = ll_back_merge_fn;
- q->front_merge_fn = ll_front_merge_fn;
- q->merge_requests_fn = ll_merge_requests_fn;
- q->make_request_fn = __make_request;
- q->plug_tq.sync = 0;
- q->plug_tq.routine = &generic_unplug_device;
- q->plug_tq.data = q;
- q->plugged = 0;
- /*
- * These booleans describe the queue properties. We set the
- * default (and most common) values here. Other drivers can
- * use the appropriate functions to alter the queue properties.
- * as appropriate.
- */
- q->plug_device_fn = generic_plug_device;
- q->head_active = 1;
-
- blk_queue_bounce_limit(q, BLK_BOUNCE_HIGH);
-}
-
-#define blkdev_free_rq(list) list_entry((list)->next, struct request, queue);
-/*
- * Get a free request. io_request_lock must be held and interrupts
- * disabled on the way in. Returns NULL if there are no free requests.
- */
-static struct request *get_request(request_queue_t *q, int rw)
-{
- struct request *rq = NULL;
- struct request_list *rl = q->rq + rw;
-
- if (!list_empty(&rl->free)) {
- rq = blkdev_free_rq(&rl->free);
- list_del(&rq->queue);
- rl->count--;
- rq->rq_status = RQ_ACTIVE;
- rq->cmd = rw;
- rq->special = NULL;
- rq->q = q;
- }
-
- return rq;
-}
-
-/*
- * Here's the request allocation design:
- *
- * 1: Blocking on request exhaustion is a key part of I/O throttling.
- *
- * 2: We want to be `fair' to all requesters. We must avoid starvation, and
- * attempt to ensure that all requesters sleep for a similar duration. Hence
- * no stealing requests when there are other processes waiting.
- *
- * 3: We also wish to support `batching' of requests. So when a process is
- * woken, we want to allow it to allocate a decent number of requests
- * before it blocks again, so they can be nicely merged (this only really
- * matters if the process happens to be adding requests near the head of
- * the queue).
- *
- * 4: We want to avoid scheduling storms. This isn't really important, because
- * the system will be I/O bound anyway. But it's easy.
- *
- * There is tension between requirements 2 and 3. Once a task has woken,
- * we don't want to allow it to sleep as soon as it takes its second request.
- * But we don't want currently-running tasks to steal all the requests
- * from the sleepers. We handle this with wakeup hysteresis around
- * 0 .. batch_requests and with the assumption that request taking is much,
- * much faster than request freeing.
- *
- * So here's what we do:
- *
- * a) A READA requester fails if free_requests < batch_requests
- *
- * We don't want READA requests to prevent sleepers from ever
- * waking. Note that READA is used extremely rarely - a few
- * filesystems use it for directory readahead.
- *
- * When a process wants a new request:
- *
- * b) If free_requests == 0, the requester sleeps in FIFO manner.
- *
- * b) If 0 < free_requests < batch_requests and there are waiters,
- * we still take a request non-blockingly. This provides batching.
- *
- * c) If free_requests >= batch_requests, the caller is immediately
- * granted a new request.
- *
- * When a request is released:
- *
- * d) If free_requests < batch_requests, do nothing.
- *
- * f) If free_requests >= batch_requests, wake up a single waiter.
- *
- * The net effect is that when a process is woken at the batch_requests level,
- * it will be able to take approximately (batch_requests) requests before
- * blocking again (at the tail of the queue).
- *
- * This all assumes that the rate of taking requests is much, much higher
- * than the rate of releasing them. Which is very true.
- *
- * -akpm, Feb 2002.
- */
-
-static struct request *__get_request_wait(request_queue_t *q, int rw)
-{
- register struct request *rq;
- DECLARE_WAITQUEUE(wait, current);
-
- generic_unplug_device(q);
- add_wait_queue_exclusive(&q->wait_for_requests[rw], &wait);
- do {
- set_current_state(TASK_UNINTERRUPTIBLE);
- if (q->rq[rw].count == 0)
- schedule();
- spin_lock_irq(&io_request_lock);
- rq = get_request(q, rw);
- spin_unlock_irq(&io_request_lock);
- } while (rq == NULL);
- remove_wait_queue(&q->wait_for_requests[rw], &wait);
- current->state = TASK_RUNNING;
- return rq;
-}
-
-/* RO fail safe mechanism */
-
-static long ro_bits[MAX_BLKDEV][8];
-
-int is_read_only(kdev_t dev)
-{
- int minor,major;
-
- major = MAJOR(dev);
- minor = MINOR(dev);
- if (major < 0 || major >= MAX_BLKDEV) return 0;
- return ro_bits[major][minor >> 5] & (1 << (minor & 31));
-}
-
-void set_device_ro(kdev_t dev,int flag)
-{
- int minor,major;
-
- major = MAJOR(dev);
- minor = MINOR(dev);
- if (major < 0 || major >= MAX_BLKDEV) return;
- if (flag) ro_bits[major][minor >> 5] |= 1 << (minor & 31);
- else ro_bits[major][minor >> 5] &= ~(1 << (minor & 31));
-}
-
-inline void drive_stat_acct (kdev_t dev, int rw,
- unsigned long nr_sectors, int new_io)
-{
- unsigned int major = MAJOR(dev);
- unsigned int index;
-
- index = disk_index(dev);
- if ((index >= DK_MAX_DISK) || (major >= DK_MAX_MAJOR))
- return;
-
- kstat.dk_drive[major][index] += new_io;
- if (rw == READ) {
- kstat.dk_drive_rio[major][index] += new_io;
- kstat.dk_drive_rblk[major][index] += nr_sectors;
- } else if (rw == WRITE) {
- kstat.dk_drive_wio[major][index] += new_io;
- kstat.dk_drive_wblk[major][index] += nr_sectors;
- } else
- printk(KERN_ERR "drive_stat_acct: cmd not R/W?\n");
-}
-
-#ifdef CONFIG_BLK_STATS
-/*
- * Return up to two hd_structs on which to do IO accounting for a given
- * request.
- *
- * On a partitioned device, we want to account both against the partition
- * and against the whole disk.
- */
-static void locate_hd_struct(struct request *req,
- struct hd_struct **hd1,
- struct hd_struct **hd2)
-{
- struct gendisk *gd;
-
- *hd1 = NULL;
- *hd2 = NULL;
-
- gd = get_gendisk(req->rq_dev);
- if (gd && gd->part) {
- /* Mask out the partition bits: account for the entire disk */
- int devnr = MINOR(req->rq_dev) >> gd->minor_shift;
- int whole_minor = devnr << gd->minor_shift;
-
- *hd1 = &gd->part[whole_minor];
- if (whole_minor != MINOR(req->rq_dev))
- *hd2= &gd->part[MINOR(req->rq_dev)];
- }
-}
-
-/*
- * Round off the performance stats on an hd_struct.
- *
- * The average IO queue length and utilisation statistics are maintained
- * by observing the current state of the queue length and the amount of
- * time it has been in this state for.
- * Normally, that accounting is done on IO completion, but that can result
- * in more than a second's worth of IO being accounted for within any one
- * second, leading to >100% utilisation. To deal with that, we do a
- * round-off before returning the results when reading /proc/partitions,
- * accounting immediately for all queue usage up to the current jiffies and
- * restarting the counters again.
- */
-void disk_round_stats(struct hd_struct *hd)
-{
- unsigned long now = jiffies;
-
- hd->aveq += (hd->ios_in_flight * (jiffies - hd->last_queue_change));
- hd->last_queue_change = now;
-
- if (hd->ios_in_flight)
- hd->io_ticks += (now - hd->last_idle_time);
- hd->last_idle_time = now;
-}
-
-static inline void down_ios(struct hd_struct *hd)
-{
- disk_round_stats(hd);
- --hd->ios_in_flight;
-}
-
-static inline void up_ios(struct hd_struct *hd)
-{
- disk_round_stats(hd);
- ++hd->ios_in_flight;
-}
-
-static void account_io_start(struct hd_struct *hd, struct request *req,
- int merge, int sectors)
-{
- switch (req->cmd) {
- case READ:
- if (merge)
- hd->rd_merges++;
- hd->rd_sectors += sectors;
- break;
- case WRITE:
- if (merge)
- hd->wr_merges++;
- hd->wr_sectors += sectors;
- break;
- }
- if (!merge)
- up_ios(hd);
-}
-
-static void account_io_end(struct hd_struct *hd, struct request *req)
-{
- unsigned long duration = jiffies - req->start_time;
- switch (req->cmd) {
- case READ:
- hd->rd_ticks += duration;
- hd->rd_ios++;
- break;
- case WRITE:
- hd->wr_ticks += duration;
- hd->wr_ios++;
- break;
- }
- down_ios(hd);
-}
-
-void req_new_io(struct request *req, int merge, int sectors)
-{
- struct hd_struct *hd1, *hd2;
-
- locate_hd_struct(req, &hd1, &hd2);
- if (hd1)
- account_io_start(hd1, req, merge, sectors);
- if (hd2)
- account_io_start(hd2, req, merge, sectors);
-}
-
-void req_merged_io(struct request *req)
-{
- struct hd_struct *hd1, *hd2;
-
- locate_hd_struct(req, &hd1, &hd2);
- if (hd1)
- down_ios(hd1);
- if (hd2)
- down_ios(hd2);
-}
-
-void req_finished_io(struct request *req)
-{
- struct hd_struct *hd1, *hd2;
-
- locate_hd_struct(req, &hd1, &hd2);
- if (hd1)
- account_io_end(hd1, req);
- if (hd2)
- account_io_end(hd2, req);
-}
-EXPORT_SYMBOL(req_finished_io);
-#endif /* CONFIG_BLK_STATS */
-
-/*
- * add-request adds a request to the linked list.
- * io_request_lock is held and interrupts disabled, as we muck with the
- * request queue list.
- *
- * By this point, req->cmd is always either READ/WRITE, never READA,
- * which is important for drive_stat_acct() above.
- */
-static inline void add_request(request_queue_t * q, struct request * req,
- struct list_head *insert_here)
-{
- drive_stat_acct(req->rq_dev, req->cmd, req->nr_sectors, 1);
-
- if (!q->plugged && q->head_active && insert_here == &q->queue_head) {
- spin_unlock_irq(&io_request_lock);
- printk("list_empty(&q->queue_head) is %d\n",
- list_empty(&q->queue_head));
- BUG();
- }
-
- /*
- * elevator indicated where it wants this request to be
- * inserted at elevator_merge time
- */
- list_add(&req->queue, insert_here);
-}
-
-/*
- * Must be called with io_request_lock held and interrupts disabled
- */
-void blkdev_release_request(struct request *req)
-{
- request_queue_t *q = req->q;
- int rw = req->cmd;
-
- req->rq_status = RQ_INACTIVE;
- req->q = NULL;
-
- /*
- * Request may not have originated from ll_rw_blk. if not,
- * assume it has free buffers and check waiters
- */
- if (q) {
- list_add(&req->queue, &q->rq[rw].free);
- if (++q->rq[rw].count >= q->batch_requests &&
- waitqueue_active(&q->wait_for_requests[rw]))
- wake_up(&q->wait_for_requests[rw]);
- }
-}
-
-/*
- * Has to be called with the request spinlock acquired
- */
-static void attempt_merge(request_queue_t * q,
- struct request *req,
- int max_sectors,
- int max_segments)
-{
- struct request *next;
-
- next = blkdev_next_request(req);
- if (req->sector + req->nr_sectors != next->sector)
- return;
- if (req->cmd != next->cmd
- || req->rq_dev != next->rq_dev
- || req->nr_sectors + next->nr_sectors > max_sectors
- || next->waiting)
- return;
- /*
- * If we are not allowed to merge these requests, then
- * return. If we are allowed to merge, then the count
- * will have been updated to the appropriate number,
- * and we shouldn't do it here too.
- */
- if (!q->merge_requests_fn(q, req, next, max_segments))
- return;
-
- q->elevator.elevator_merge_req_fn(req, next);
- req->bhtail->b_reqnext = next->bh;
- req->bhtail = next->bhtail;
- req->nr_sectors = req->hard_nr_sectors += next->hard_nr_sectors;
- list_del(&next->queue);
-
- /* One last thing: we have removed a request, so we now have one
- less expected IO to complete for accounting purposes. */
- req_merged_io(req);
-
- blkdev_release_request(next);
-}
-
-static inline void attempt_back_merge(request_queue_t * q,
- struct request *req,
- int max_sectors,
- int max_segments)
-{
- if (&req->queue == q->queue_head.prev)
- return;
- attempt_merge(q, req, max_sectors, max_segments);
-}
-
-static inline void attempt_front_merge(request_queue_t * q,
- struct list_head * head,
- struct request *req,
- int max_sectors,
- int max_segments)
-{
- struct list_head * prev;
-
- prev = req->queue.prev;
- if (head == prev)
- return;
- attempt_merge(q, blkdev_entry_to_request(prev), max_sectors, max_segments);
-}
-
-static int __make_request(request_queue_t * q, int rw,
- struct buffer_head * bh)
-{
- unsigned int sector, count;
- int max_segments = MAX_SEGMENTS;
- struct request * req, *freereq = NULL;
- int rw_ahead, max_sectors, el_ret;
- struct list_head *head, *insert_here;
- int latency;
- elevator_t *elevator = &q->elevator;
-
- count = bh->b_size >> 9;
- sector = bh->b_rsector;
-
- rw_ahead = 0; /* normal case; gets changed below for READA */
- switch (rw) {
- case READA:
-#if 0 /* bread() misinterprets failed READA attempts as IO errors on SMP */
- rw_ahead = 1;
-#endif
- rw = READ; /* drop into READ */
- case READ:
- case WRITE:
- latency = elevator_request_latency(elevator, rw);
- break;
- default:
- BUG();
- goto end_io;
- }
-
- /* We'd better have a real physical mapping!
- Check this bit only if the buffer was dirty and just locked
- down by us so at this point flushpage will block and
- won't clear the mapped bit under us. */
- if (!buffer_mapped(bh))
- BUG();
-
- /*
- * Temporary solution - in 2.5 this will be done by the lowlevel
- * driver. Create a bounce buffer if the buffer data points into
- * high memory - keep the original buffer otherwise.
- */
- bh = blk_queue_bounce(q, rw, bh);
-
-/* look for a free request. */
- /*
- * Try to coalesce the new request with old requests
- */
- max_sectors = get_max_sectors(bh->b_rdev);
-
-again:
- req = NULL;
- head = &q->queue_head;
- /*
- * Now we acquire the request spinlock, we have to be mega careful
- * not to schedule or do something nonatomic
- */
- spin_lock_irq(&io_request_lock);
-
- insert_here = head->prev;
- if (list_empty(head)) {
- q->plug_device_fn(q, bh->b_rdev); /* is atomic */
- goto get_rq;
- } else if (q->head_active && !q->plugged)
- head = head->next;
-
- el_ret = elevator->elevator_merge_fn(q, &req, head, bh, rw,max_sectors);
- switch (el_ret) {
-
- case ELEVATOR_BACK_MERGE:
- if (!q->back_merge_fn(q, req, bh, max_segments)) {
- insert_here = &req->queue;
- break;
- }
- req->bhtail->b_reqnext = bh;
- req->bhtail = bh;
- req->nr_sectors = req->hard_nr_sectors += count;
- blk_started_io(count);
- drive_stat_acct(req->rq_dev, req->cmd, count, 0);
- req_new_io(req, 1, count);
- attempt_back_merge(q, req, max_sectors, max_segments);
- goto out;
-
- case ELEVATOR_FRONT_MERGE:
- if (!q->front_merge_fn(q, req, bh, max_segments)) {
- insert_here = req->queue.prev;
- break;
- }
- bh->b_reqnext = req->bh;
- req->bh = bh;
- /*
- * may not be valid, but queues not having bounce
- * enabled for highmem pages must not look at
- * ->buffer anyway
- */
- req->buffer = bh->b_data;
- req->current_nr_sectors = req->hard_cur_sectors = count;
- req->sector = req->hard_sector = sector;
- req->nr_sectors = req->hard_nr_sectors += count;
- blk_started_io(count);
- drive_stat_acct(req->rq_dev, req->cmd, count, 0);
- req_new_io(req, 1, count);
- attempt_front_merge(q, head, req, max_sectors, max_segments);
- goto out;
-
- /*
- * elevator says don't/can't merge. get new request
- */
- case ELEVATOR_NO_MERGE:
- /*
- * use elevator hints as to where to insert the
- * request. if no hints, just add it to the back
- * of the queue
- */
- if (req)
- insert_here = &req->queue;
- break;
-
- default:
- printk("elevator returned crap (%d)\n", el_ret);
- BUG();
- }
-
-get_rq:
- if (freereq) {
- req = freereq;
- freereq = NULL;
- } else {
- /*
- * See description above __get_request_wait()
- */
- if (rw_ahead) {
- if (q->rq[rw].count < q->batch_requests) {
- spin_unlock_irq(&io_request_lock);
- goto end_io;
- }
- req = get_request(q, rw);
- if (req == NULL)
- BUG();
- } else {
- req = get_request(q, rw);
- if (req == NULL) {
- spin_unlock_irq(&io_request_lock);
- freereq = __get_request_wait(q, rw);
- goto again;
- }
- }
- }
-
-/* fill up the request-info, and add it to the queue */
- req->elevator_sequence = latency;
- req->cmd = rw;
- req->errors = 0;
- req->hard_sector = req->sector = sector;
- req->hard_nr_sectors = req->nr_sectors = count;
- req->current_nr_sectors = req->hard_cur_sectors = count;
- req->nr_segments = 1; /* Always 1 for a new request. */
- req->nr_hw_segments = 1; /* Always 1 for a new request. */
- req->buffer = bh->b_data;
- req->waiting = NULL;
- req->bh = bh;
- req->bhtail = bh;
- req->rq_dev = bh->b_rdev;
- req->start_time = jiffies;
- req_new_io(req, 0, count);
- blk_started_io(count);
- add_request(q, req, insert_here);
-out:
- if (freereq)
- blkdev_release_request(freereq);
- spin_unlock_irq(&io_request_lock);
- return 0;
-end_io:
- bh->b_end_io(bh, test_bit(BH_Uptodate, &bh->b_state));
- return 0;
-}
-
-/**
- * generic_make_request: hand a buffer head to it's device driver for I/O
- * @rw: READ, WRITE, or READA - what sort of I/O is desired.
- * @bh: The buffer head describing the location in memory and on the device.
- *
- * generic_make_request() is used to make I/O requests of block
- * devices. It is passed a &struct buffer_head and a &rw value. The
- * %READ and %WRITE options are (hopefully) obvious in meaning. The
- * %READA value means that a read is required, but that the driver is
- * free to fail the request if, for example, it cannot get needed
- * resources immediately.
- *
- * generic_make_request() does not return any status. The
- * success/failure status of the request, along with notification of
- * completion, is delivered asynchronously through the bh->b_end_io
- * function described (one day) else where.
- *
- * The caller of generic_make_request must make sure that b_page,
- * b_addr, b_size are set to describe the memory buffer, that b_rdev
- * and b_rsector are set to describe the device address, and the
- * b_end_io and optionally b_private are set to describe how
- * completion notification should be signaled. BH_Mapped should also
- * be set (to confirm that b_dev and b_blocknr are valid).
- *
- * generic_make_request and the drivers it calls may use b_reqnext,
- * and may change b_rdev and b_rsector. So the values of these fields
- * should NOT be depended on after the call to generic_make_request.
- * Because of this, the caller should record the device address
- * information in b_dev and b_blocknr.
- *
- * Apart from those fields mentioned above, no other fields, and in
- * particular, no other flags, are changed by generic_make_request or
- * any lower level drivers.
- * */
-void generic_make_request (int rw, struct buffer_head * bh)
-{
- int major = MAJOR(bh->b_rdev);
- int minorsize = 0;
- request_queue_t *q;
-
- if (!bh->b_end_io)
- BUG();
-
- /* Test device size, when known. */
- if (blk_size[major])
- minorsize = blk_size[major][MINOR(bh->b_rdev)];
- if (minorsize) {
- unsigned long maxsector = (minorsize << 1) + 1;
- unsigned long sector = bh->b_rsector;
- unsigned int count = bh->b_size >> 9;
-
- if (maxsector < count || maxsector - count < sector) {
- /* Yecch */
- bh->b_state &= (1 << BH_Lock) | (1 << BH_Mapped);
-
- /* This may well happen - the kernel calls bread()
- without checking the size of the device, e.g.,
- when mounting a device. */
- printk(KERN_INFO
- "attempt to access beyond end of device\n");
- printk(KERN_INFO "%s: rw=%d, want=%ld, limit=%d\n",
- kdevname(bh->b_rdev), rw,
- (sector + count)>>1, minorsize);
-
- /* Yecch again */
- bh->b_end_io(bh, 0);
- return;
- }
- }
-
- /*
- * Resolve the mapping until finished. (drivers are
- * still free to implement/resolve their own stacking
- * by explicitly returning 0)
- */
- /* NOTE: we don't repeat the blk_size check for each new device.
- * Stacking drivers are expected to know what they are doing.
- */
- do {
- q = blk_get_queue(bh->b_rdev);
- if (!q) {
- printk(KERN_ERR
- "generic_make_request: Trying to access "
- "nonexistent block-device %s (%ld)\n",
- kdevname(bh->b_rdev), bh->b_rsector);
- buffer_IO_error(bh);
- break;
- }
- } while (q->make_request_fn(q, rw, bh));
-}
-
-
-/**
- * submit_bh: submit a buffer_head to the block device later for I/O
- * @rw: whether to %READ or %WRITE, or maybe to %READA (read ahead)
- * @bh: The &struct buffer_head which describes the I/O
- *
- * submit_bh() is very similar in purpose to generic_make_request(), and
- * uses that function to do most of the work.
- *
- * The extra functionality provided by submit_bh is to determine
- * b_rsector from b_blocknr and b_size, and to set b_rdev from b_dev.
- * This is is appropriate for IO requests that come from the buffer
- * cache and page cache which (currently) always use aligned blocks.
- */
-void submit_bh(int rw, struct buffer_head * bh)
-{
- int count = bh->b_size >> 9;
-
- if (!test_bit(BH_Lock, &bh->b_state))
- BUG();
-
- set_bit(BH_Req, &bh->b_state);
- set_bit(BH_Launder, &bh->b_state);
-
- /*
- * First step, 'identity mapping' - RAID or LVM might
- * further remap this.
- */
- bh->b_rdev = bh->b_dev;
- bh->b_rsector = bh->b_blocknr * count;
-
- generic_make_request(rw, bh);
-
- switch (rw) {
- case WRITE:
- kstat.pgpgout += count;
- break;
- default:
- kstat.pgpgin += count;
- break;
- }
-}
-
-/**
- * ll_rw_block: low-level access to block devices
- * @rw: whether to %READ or %WRITE or maybe %READA (readahead)
- * @nr: number of &struct buffer_heads in the array
- * @bhs: array of pointers to &struct buffer_head
- *
- * ll_rw_block() takes an array of pointers to &struct buffer_heads,
- * and requests an I/O operation on them, either a %READ or a %WRITE.
- * The third %READA option is described in the documentation for
- * generic_make_request() which ll_rw_block() calls.
- *
- * This function provides extra functionality that is not in
- * generic_make_request() that is relevant to buffers in the buffer
- * cache or page cache. In particular it drops any buffer that it
- * cannot get a lock on (with the BH_Lock state bit), any buffer that
- * appears to be clean when doing a write request, and any buffer that
- * appears to be up-to-date when doing read request. Further it marks
- * as clean buffers that are processed for writing (the buffer cache
- * wont assume that they are actually clean until the buffer gets
- * unlocked).
- *
- * ll_rw_block sets b_end_io to simple completion handler that marks
- * the buffer up-to-date (if approriate), unlocks the buffer and wakes
- * any waiters. As client that needs a more interesting completion
- * routine should call submit_bh() (or generic_make_request())
- * directly.
- *
- * Caveat:
- * All of the buffers must be for the same device, and must also be
- * of the current approved size for the device. */
-
-void ll_rw_block(int rw, int nr, struct buffer_head * bhs[])
-{
- unsigned int major;
- int correct_size;
- int i;
-
- if (!nr)
- return;
-
- major = MAJOR(bhs[0]->b_dev);
-
- /* Determine correct block size for this device. */
- correct_size = get_hardsect_size(bhs[0]->b_dev);
-
- /* Verify requested block sizes. */
- for (i = 0; i < nr; i++) {
- struct buffer_head *bh = bhs[i];
- if (bh->b_size % correct_size) {
- printk(KERN_NOTICE "ll_rw_block: device %s: "
- "only %d-char blocks implemented (%u)\n",
- kdevname(bhs[0]->b_dev),
- correct_size, bh->b_size);
- goto sorry;
- }
- }
-
- if ((rw & WRITE) && is_read_only(bhs[0]->b_dev)) {
- printk(KERN_NOTICE "Can't write to read-only device %s\n",
- kdevname(bhs[0]->b_dev));
- goto sorry;
- }
-
- for (i = 0; i < nr; i++) {
- struct buffer_head *bh = bhs[i];
-
- /* Only one thread can actually submit the I/O. */
- if (test_and_set_bit(BH_Lock, &bh->b_state))
- continue;
-
- /* We have the buffer lock */
- atomic_inc(&bh->b_count);
- bh->b_end_io = end_buffer_io_sync;
-
- switch(rw) {
- case WRITE:
- if (!atomic_set_buffer_clean(bh))
- /* Hmmph! Nothing to write */
- goto end_io;
- __mark_buffer_clean(bh);
- break;
-
- case READA:
- case READ:
- if (buffer_uptodate(bh))
- /* Hmmph! Already have it */
- goto end_io;
- break;
- default:
- BUG();
- end_io:
- bh->b_end_io(bh, test_bit(BH_Uptodate, &bh->b_state));
- continue;
- }
-
- submit_bh(rw, bh);
- }
- return;
-
-sorry:
- /* Make sure we don't get infinite dirty retries.. */
- for (i = 0; i < nr; i++)
- mark_buffer_clean(bhs[i]);
-}
-
-#ifdef CONFIG_STRAM_SWAP
-extern int stram_device_init (void);
-#endif
-
-
-/**
- * end_that_request_first - end I/O on one buffer.
- * @req: the request being processed
- * @uptodate: 0 for I/O error
- * @name: the name printed for an I/O error
- *
- * Description:
- * Ends I/O on the first buffer attached to @req, and sets it up
- * for the next buffer_head (if any) in the cluster.
- *
- * Return:
- * 0 - we are done with this request, call end_that_request_last()
- * 1 - still buffers pending for this request
- *
- * Caveat:
- * Drivers implementing their own end_request handling must call
- * blk_finished_io() appropriately.
- **/
-
-int end_that_request_first (struct request *req, int uptodate, char *name)
-{
- struct buffer_head * bh;
- int nsect;
-
- req->errors = 0;
- if (!uptodate)
- printk("end_request: I/O error, dev %s (%s), sector %lu\n",
- kdevname(req->rq_dev), name, req->sector);
-
- if ((bh = req->bh) != NULL) {
- nsect = bh->b_size >> 9;
- blk_finished_io(nsect);
- req->bh = bh->b_reqnext;
- bh->b_reqnext = NULL;
- bh->b_end_io(bh, uptodate);
- if ((bh = req->bh) != NULL) {
- req->hard_sector += nsect;
- req->hard_nr_sectors -= nsect;
- req->sector = req->hard_sector;
- req->nr_sectors = req->hard_nr_sectors;
-
- req->current_nr_sectors = bh->b_size >> 9;
- req->hard_cur_sectors = req->current_nr_sectors;
- if (req->nr_sectors < req->current_nr_sectors) {
- req->nr_sectors = req->current_nr_sectors;
- printk("end_request: buffer-list destroyed\n");
- }
- req->buffer = bh->b_data;
- return 1;
- }
- }
- return 0;
-}
-
-void end_that_request_last(struct request *req)
-{
- if (req->waiting != NULL)
- complete(req->waiting);
- req_finished_io(req);
-
- blkdev_release_request(req);
-}
-
-int __init blk_dev_init(void)
-{
- struct blk_dev_struct *dev;
-
- request_cachep = kmem_cache_create("blkdev_requests",
- sizeof(struct request),
- 0, SLAB_HWCACHE_ALIGN, NULL, NULL);
-
- if (!request_cachep)
- panic("Can't create request pool slab cache\n");
-
- for (dev = blk_dev + MAX_BLKDEV; dev-- != blk_dev;)
- dev->queue = NULL;
-
- memset(ro_bits,0,sizeof(ro_bits));
- memset(max_readahead, 0, sizeof(max_readahead));
- memset(max_sectors, 0, sizeof(max_sectors));
-
- blk_max_low_pfn = max_low_pfn - 1;
- blk_max_pfn = max_pfn - 1;
-
-#ifdef CONFIG_AMIGA_Z2RAM
- z2_init();
-#endif
-#ifdef CONFIG_STRAM_SWAP
- stram_device_init();
-#endif
-#ifdef CONFIG_ISP16_CDI
- isp16_init();
-#endif
-#ifdef CONFIG_BLK_DEV_PS2
- ps2esdi_init();
-#endif
-#ifdef CONFIG_BLK_DEV_XD
- xd_init();
-#endif
-#ifdef CONFIG_BLK_DEV_MFM
- mfm_init();
-#endif
-#ifdef CONFIG_PARIDE
- { extern void paride_init(void); paride_init(); };
-#endif
-#ifdef CONFIG_MAC_FLOPPY
- swim3_init();
-#endif
-#ifdef CONFIG_BLK_DEV_SWIM_IOP
- swimiop_init();
-#endif
-#ifdef CONFIG_AMIGA_FLOPPY
- amiga_floppy_init();
-#endif
-#ifdef CONFIG_ATARI_FLOPPY
- atari_floppy_init();
-#endif
-#ifdef CONFIG_BLK_DEV_FD
- floppy_init();
-#else
-#if defined(__i386__) && !defined(CONFIG_XENO) /* Do we even need this? */
- outb_p(0xc, 0x3f2);
-#endif
-#endif
-#ifdef CONFIG_CDU31A
- cdu31a_init();
-#endif
-#ifdef CONFIG_ATARI_ACSI
- acsi_init();
-#endif
-#ifdef CONFIG_MCD
- mcd_init();
-#endif
-#ifdef CONFIG_MCDX
- mcdx_init();
-#endif
-#ifdef CONFIG_SBPCD
- sbpcd_init();
-#endif
-#ifdef CONFIG_AZTCD
- aztcd_init();
-#endif
-#ifdef CONFIG_CDU535
- sony535_init();
-#endif
-#ifdef CONFIG_GSCD
- gscd_init();
-#endif
-#ifdef CONFIG_CM206
- cm206_init();
-#endif
-#ifdef CONFIG_OPTCD
- optcd_init();
-#endif
-#ifdef CONFIG_SJCD
- sjcd_init();
-#endif
-#ifdef CONFIG_APBLOCK
- ap_init();
-#endif
-#ifdef CONFIG_DDV
- ddv_init();
-#endif
-#ifdef CONFIG_MDISK
- mdisk_init();
-#endif
-#ifdef CONFIG_DASD
- dasd_init();
-#endif
-#if defined(CONFIG_S390_TAPE) && defined(CONFIG_S390_TAPE_BLOCK)
- tapeblock_init();
-#endif
-#ifdef CONFIG_BLK_DEV_XPRAM
- xpram_init();
-#endif
-
-#ifdef CONFIG_SUN_JSFLASH
- jsfd_init();
-#endif
-
-#ifdef CONFIG_XENOLINUX_BLOCK
- xlblk_init();
- xlseg_init();
- xlseg_proc_init();
-#endif
-
- return 0;
-};
-
-EXPORT_SYMBOL(io_request_lock);
-EXPORT_SYMBOL(end_that_request_first);
-EXPORT_SYMBOL(end_that_request_last);
-EXPORT_SYMBOL(blk_grow_request_list);
-EXPORT_SYMBOL(blk_init_queue);
-EXPORT_SYMBOL(blk_get_queue);
-EXPORT_SYMBOL(blk_cleanup_queue);
-EXPORT_SYMBOL(blk_queue_headactive);
-EXPORT_SYMBOL(blk_queue_make_request);
-EXPORT_SYMBOL(generic_make_request);
-EXPORT_SYMBOL(blkdev_release_request);
-EXPORT_SYMBOL(generic_unplug_device);
-EXPORT_SYMBOL(blk_queue_bounce_limit);
-EXPORT_SYMBOL(blk_max_low_pfn);
-EXPORT_SYMBOL(blk_max_pfn);
-EXPORT_SYMBOL(blk_seg_merge_ok);
-EXPORT_SYMBOL(blk_nohighio);
+++ /dev/null
-/*
- * linux/drivers/char/tty_io.c
- *
- * Copyright (C) 1991, 1992 Linus Torvalds
- */
-
-/*
- * 'tty_io.c' gives an orthogonal feeling to tty's, be they consoles
- * or rs-channels. It also implements echoing, cooked mode etc.
- *
- * Kill-line thanks to John T Kohl, who also corrected VMIN = VTIME = 0.
- *
- * Modified by Theodore Ts'o, 9/14/92, to dynamically allocate the
- * tty_struct and tty_queue structures. Previously there was an array
- * of 256 tty_struct's which was statically allocated, and the
- * tty_queue structures were allocated at boot time. Both are now
- * dynamically allocated only when the tty is open.
- *
- * Also restructured routines so that there is more of a separation
- * between the high-level tty routines (tty_io.c and tty_ioctl.c) and
- * the low-level tty routines (serial.c, pty.c, console.c). This
- * makes for cleaner and more compact code. -TYT, 9/17/92
- *
- * Modified by Fred N. van Kempen, 01/29/93, to add line disciplines
- * which can be dynamically activated and de-activated by the line
- * discipline handling modules (like SLIP).
- *
- * NOTE: pay no attention to the line discipline code (yet); its
- * interface is still subject to change in this version...
- * -- TYT, 1/31/92
- *
- * Added functionality to the OPOST tty handling. No delays, but all
- * other bits should be there.
- * -- Nick Holloway <alfie@dcs.warwick.ac.uk>, 27th May 1993.
- *
- * Rewrote canonical mode and added more termios flags.
- * -- julian@uhunix.uhcc.hawaii.edu (J. Cowley), 13Jan94
- *
- * Reorganized FASYNC support so mouse code can share it.
- * -- ctm@ardi.com, 9Sep95
- *
- * New TIOCLINUX variants added.
- * -- mj@k332.feld.cvut.cz, 19-Nov-95
- *
- * Restrict vt switching via ioctl()
- * -- grif@cs.ucr.edu, 5-Dec-95
- *
- * Move console and virtual terminal code to more appropriate files,
- * implement CONFIG_VT and generalize console device interface.
- * -- Marko Kohtala <Marko.Kohtala@hut.fi>, March 97
- *
- * Rewrote init_dev and release_dev to eliminate races.
- * -- Bill Hawes <whawes@star.net>, June 97
- *
- * Added devfs support.
- * -- C. Scott Ananian <cananian@alumni.princeton.edu>, 13-Jan-1998
- *
- * Added support for a Unix98-style ptmx device.
- * -- C. Scott Ananian <cananian@alumni.princeton.edu>, 14-Jan-1998
- *
- * Reduced memory usage for older ARM systems
- * -- Russell King <rmk@arm.linux.org.uk>
- *
- * Move do_SAK() into process context. Less stack use in devfs functions.
- * alloc_tty_struct() always uses kmalloc() -- Andrew Morton <andrewm@uow.edu.eu> 17Mar01
- */
-
-#include <linux/config.h>
-#include <linux/types.h>
-#include <linux/major.h>
-#include <linux/errno.h>
-#include <linux/signal.h>
-#include <linux/fcntl.h>
-#include <linux/sched.h>
-#include <linux/interrupt.h>
-#include <linux/tty.h>
-#include <linux/tty_driver.h>
-#include <linux/tty_flip.h>
-#include <linux/devpts_fs.h>
-#include <linux/file.h>
-#include <linux/console.h>
-#include <linux/timer.h>
-#include <linux/ctype.h>
-#include <linux/kd.h>
-#include <linux/mm.h>
-#include <linux/string.h>
-#include <linux/slab.h>
-#include <linux/poll.h>
-#include <linux/proc_fs.h>
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/smp_lock.h>
-
-#include <asm/uaccess.h>
-#include <asm/system.h>
-#include <asm/bitops.h>
-
-#include <linux/kbd_kern.h>
-#include <linux/vt_kern.h>
-#include <linux/selection.h>
-#include <linux/devfs_fs_kernel.h>
-
-#include <linux/kmod.h>
-
-#ifdef CONFIG_XEN_CONSOLE
-extern void xen_console_init(void);
-#endif
-
-#ifdef CONFIG_VT
-extern void con_init_devfs (void);
-#endif
-
-extern void disable_early_printk(void);
-
-#define CONSOLE_DEV MKDEV(TTY_MAJOR,0)
-#define TTY_DEV MKDEV(TTYAUX_MAJOR,0)
-#define SYSCONS_DEV MKDEV(TTYAUX_MAJOR,1)
-#define PTMX_DEV MKDEV(TTYAUX_MAJOR,2)
-
-#undef TTY_DEBUG_HANGUP
-
-#define TTY_PARANOIA_CHECK 1
-#define CHECK_TTY_COUNT 1
-
-struct termios tty_std_termios; /* for the benefit of tty drivers */
-struct tty_driver *tty_drivers; /* linked list of tty drivers */
-struct tty_ldisc ldiscs[NR_LDISCS]; /* line disc dispatch table */
-
-#ifdef CONFIG_UNIX98_PTYS
-extern struct tty_driver ptm_driver[]; /* Unix98 pty masters; for /dev/ptmx */
-extern struct tty_driver pts_driver[]; /* Unix98 pty slaves; for /dev/ptmx */
-#endif
-
-/*
- * redirect is the pseudo-tty that console output
- * is redirected to if asked by TIOCCONS.
- */
-struct tty_struct * redirect;
-
-static void initialize_tty_struct(struct tty_struct *tty);
-
-static ssize_t tty_read(struct file *, char *, size_t, loff_t *);
-static ssize_t tty_write(struct file *, const char *, size_t, loff_t *);
-static unsigned int tty_poll(struct file *, poll_table *);
-static int tty_open(struct inode *, struct file *);
-static int tty_release(struct inode *, struct file *);
-int tty_ioctl(struct inode * inode, struct file * file,
- unsigned int cmd, unsigned long arg);
-static int tty_fasync(int fd, struct file * filp, int on);
-extern int vme_scc_init (void);
-extern long vme_scc_console_init(void);
-extern int serial167_init(void);
-extern long serial167_console_init(void);
-extern void console_8xx_init(void);
-extern int rs_8xx_init(void);
-extern void mac_scc_console_init(void);
-extern void hwc_console_init(void);
-extern void hwc_tty_init(void);
-extern void con3215_init(void);
-extern void tty3215_init(void);
-extern void tub3270_con_init(void);
-extern void tub3270_init(void);
-extern void rs285_console_init(void);
-extern void sa1100_rs_console_init(void);
-extern void sgi_serial_console_init(void);
-extern void sci_console_init(void);
-extern void tx3912_console_init(void);
-extern void tx3912_rs_init(void);
-extern void txx927_console_init(void);
-extern void sb1250_serial_console_init(void);
-
-#ifndef MIN
-#define MIN(a,b) ((a) < (b) ? (a) : (b))
-#endif
-#ifndef MAX
-#define MAX(a,b) ((a) < (b) ? (b) : (a))
-#endif
-
-static struct tty_struct *alloc_tty_struct(void)
-{
- struct tty_struct *tty;
-
- tty = kmalloc(sizeof(struct tty_struct), GFP_KERNEL);
- if (tty)
- memset(tty, 0, sizeof(struct tty_struct));
- return tty;
-}
-
-static inline void free_tty_struct(struct tty_struct *tty)
-{
- kfree(tty);
-}
-
-/*
- * This routine returns the name of tty.
- */
-static char *
-_tty_make_name(struct tty_struct *tty, const char *name, char *buf)
-{
- int idx = (tty)?MINOR(tty->device) - tty->driver.minor_start:0;
-
- if (!tty) /* Hmm. NULL pointer. That's fun. */
- strcpy(buf, "NULL tty");
- else
- sprintf(buf, name,
- idx + tty->driver.name_base);
-
- return buf;
-}
-
-#define TTY_NUMBER(tty) (MINOR((tty)->device) - (tty)->driver.minor_start + \
- (tty)->driver.name_base)
-
-char *tty_name(struct tty_struct *tty, char *buf)
-{
- return _tty_make_name(tty, (tty)?tty->driver.name:NULL, buf);
-}
-
-inline int tty_paranoia_check(struct tty_struct *tty, kdev_t device,
- const char *routine)
-{
-#ifdef TTY_PARANOIA_CHECK
- static const char badmagic[] = KERN_WARNING
- "Warning: bad magic number for tty struct (%s) in %s\n";
- static const char badtty[] = KERN_WARNING
- "Warning: null TTY for (%s) in %s\n";
-
- if (!tty) {
- printk(badtty, kdevname(device), routine);
- return 1;
- }
- if (tty->magic != TTY_MAGIC) {
- printk(badmagic, kdevname(device), routine);
- return 1;
- }
-#endif
- return 0;
-}
-
-static int check_tty_count(struct tty_struct *tty, const char *routine)
-{
-#ifdef CHECK_TTY_COUNT
- struct list_head *p;
- int count = 0;
-
- file_list_lock();
- for(p = tty->tty_files.next; p != &tty->tty_files; p = p->next) {
- if(list_entry(p, struct file, f_list)->private_data == tty)
- count++;
- }
- file_list_unlock();
- if (tty->driver.type == TTY_DRIVER_TYPE_PTY &&
- tty->driver.subtype == PTY_TYPE_SLAVE &&
- tty->link && tty->link->count)
- count++;
- if (tty->count != count) {
- printk(KERN_WARNING "Warning: dev (%s) tty->count(%d) "
- "!= #fd's(%d) in %s\n",
- kdevname(tty->device), tty->count, count, routine);
- return count;
- }
-#endif
- return 0;
-}
-
-int tty_register_ldisc(int disc, struct tty_ldisc *new_ldisc)
-{
- if (disc < N_TTY || disc >= NR_LDISCS)
- return -EINVAL;
-
- if (new_ldisc) {
- ldiscs[disc] = *new_ldisc;
- ldiscs[disc].flags |= LDISC_FLAG_DEFINED;
- ldiscs[disc].num = disc;
- } else
- memset(&ldiscs[disc], 0, sizeof(struct tty_ldisc));
-
- return 0;
-}
-
-EXPORT_SYMBOL(tty_register_ldisc);
-
-/* Set the discipline of a tty line. */
-static int tty_set_ldisc(struct tty_struct *tty, int ldisc)
-{
- int retval = 0;
- struct tty_ldisc o_ldisc;
- char buf[64];
-
- if ((ldisc < N_TTY) || (ldisc >= NR_LDISCS))
- return -EINVAL;
- /* Eduardo Blanco <ejbs@cs.cs.com.uy> */
- /* Cyrus Durgin <cider@speakeasy.org> */
- if (!(ldiscs[ldisc].flags & LDISC_FLAG_DEFINED)) {
- char modname [20];
- sprintf(modname, "tty-ldisc-%d", ldisc);
- request_module (modname);
- }
- if (!(ldiscs[ldisc].flags & LDISC_FLAG_DEFINED))
- return -EINVAL;
-
- if (tty->ldisc.num == ldisc)
- return 0; /* We are already in the desired discipline */
- o_ldisc = tty->ldisc;
-
- tty_wait_until_sent(tty, 0);
-
- /* Shutdown the current discipline. */
- if (tty->ldisc.close)
- (tty->ldisc.close)(tty);
-
- /* Now set up the new line discipline. */
- tty->ldisc = ldiscs[ldisc];
- tty->termios->c_line = ldisc;
- if (tty->ldisc.open)
- retval = (tty->ldisc.open)(tty);
- if (retval < 0) {
- tty->ldisc = o_ldisc;
- tty->termios->c_line = tty->ldisc.num;
- if (tty->ldisc.open && (tty->ldisc.open(tty) < 0)) {
- tty->ldisc = ldiscs[N_TTY];
- tty->termios->c_line = N_TTY;
- if (tty->ldisc.open) {
- int r = tty->ldisc.open(tty);
-
- if (r < 0)
- panic("Couldn't open N_TTY ldisc for "
- "%s --- error %d.",
- tty_name(tty, buf), r);
- }
- }
- }
- if (tty->ldisc.num != o_ldisc.num && tty->driver.set_ldisc)
- tty->driver.set_ldisc(tty);
- return retval;
-}
-
-/*
- * This routine returns a tty driver structure, given a device number
- */
-struct tty_driver *get_tty_driver(kdev_t device)
-{
- int major, minor;
- struct tty_driver *p;
-
- minor = MINOR(device);
- major = MAJOR(device);
-
- for (p = tty_drivers; p; p = p->next) {
- if (p->major != major)
- continue;
- if (minor < p->minor_start)
- continue;
- if (minor >= p->minor_start + p->num)
- continue;
- return p;
- }
- return NULL;
-}
-
-/*
- * If we try to write to, or set the state of, a terminal and we're
- * not in the foreground, send a SIGTTOU. If the signal is blocked or
- * ignored, go ahead and perform the operation. (POSIX 7.2)
- */
-int tty_check_change(struct tty_struct * tty)
-{
- if (current->tty != tty)
- return 0;
- if (tty->pgrp <= 0) {
- printk(KERN_WARNING "tty_check_change: tty->pgrp <= 0!\n");
- return 0;
- }
- if (current->pgrp == tty->pgrp)
- return 0;
- if (is_ignored(SIGTTOU))
- return 0;
- if (is_orphaned_pgrp(current->pgrp))
- return -EIO;
- (void) kill_pg(current->pgrp,SIGTTOU,1);
- return -ERESTARTSYS;
-}
-
-static ssize_t hung_up_tty_read(struct file * file, char * buf,
- size_t count, loff_t *ppos)
-{
- /* Can't seek (pread) on ttys. */
- if (ppos != &file->f_pos)
- return -ESPIPE;
- return 0;
-}
-
-static ssize_t hung_up_tty_write(struct file * file, const char * buf,
- size_t count, loff_t *ppos)
-{
- /* Can't seek (pwrite) on ttys. */
- if (ppos != &file->f_pos)
- return -ESPIPE;
- return -EIO;
-}
-
-/* No kernel lock held - none needed ;) */
-static unsigned int hung_up_tty_poll(struct file * filp, poll_table * wait)
-{
- return POLLIN | POLLOUT | POLLERR | POLLHUP | POLLRDNORM | POLLWRNORM;
-}
-
-static int hung_up_tty_ioctl(struct inode * inode, struct file * file,
- unsigned int cmd, unsigned long arg)
-{
- return cmd == TIOCSPGRP ? -ENOTTY : -EIO;
-}
-
-static struct file_operations tty_fops = {
- llseek: no_llseek,
- read: tty_read,
- write: tty_write,
- poll: tty_poll,
- ioctl: tty_ioctl,
- open: tty_open,
- release: tty_release,
- fasync: tty_fasync,
-};
-
-static struct file_operations hung_up_tty_fops = {
- llseek: no_llseek,
- read: hung_up_tty_read,
- write: hung_up_tty_write,
- poll: hung_up_tty_poll,
- ioctl: hung_up_tty_ioctl,
- release: tty_release,
-};
-
-/*
- * This can be called by the "eventd" kernel thread. That is process synchronous,
- * but doesn't hold any locks, so we need to make sure we have the appropriate
- * locks for what we're doing..
- */
-void do_tty_hangup(void *data)
-{
- struct tty_struct *tty = (struct tty_struct *) data;
- struct file * cons_filp = NULL;
- struct task_struct *p;
- struct list_head *l;
- int closecount = 0, n;
-
- if (!tty)
- return;
-
- /* inuse_filps is protected by the single kernel lock */
- lock_kernel();
-
- check_tty_count(tty, "do_tty_hangup");
- file_list_lock();
- for (l = tty->tty_files.next; l != &tty->tty_files; l = l->next) {
- struct file * filp = list_entry(l, struct file, f_list);
- if (filp->f_dentry->d_inode->i_rdev == CONSOLE_DEV ||
- filp->f_dentry->d_inode->i_rdev == SYSCONS_DEV) {
- cons_filp = filp;
- continue;
- }
- if (filp->f_op != &tty_fops)
- continue;
- closecount++;
- tty_fasync(-1, filp, 0); /* can't block */
- filp->f_op = &hung_up_tty_fops;
- }
- file_list_unlock();
-
- /* FIXME! What are the locking issues here? This may me overdoing things.. */
- {
- unsigned long flags;
-
- save_flags(flags); cli();
- if (tty->ldisc.flush_buffer)
- tty->ldisc.flush_buffer(tty);
- if (tty->driver.flush_buffer)
- tty->driver.flush_buffer(tty);
- if ((test_bit(TTY_DO_WRITE_WAKEUP, &tty->flags)) &&
- tty->ldisc.write_wakeup)
- (tty->ldisc.write_wakeup)(tty);
- restore_flags(flags);
- }
-
- wake_up_interruptible(&tty->write_wait);
- wake_up_interruptible(&tty->read_wait);
-
- /*
- * Shutdown the current line discipline, and reset it to
- * N_TTY.
- */
- if (tty->driver.flags & TTY_DRIVER_RESET_TERMIOS)
- *tty->termios = tty->driver.init_termios;
- if (tty->ldisc.num != ldiscs[N_TTY].num) {
- if (tty->ldisc.close)
- (tty->ldisc.close)(tty);
- tty->ldisc = ldiscs[N_TTY];
- tty->termios->c_line = N_TTY;
- if (tty->ldisc.open) {
- int i = (tty->ldisc.open)(tty);
- if (i < 0)
- printk(KERN_ERR "do_tty_hangup: N_TTY open: "
- "error %d\n", -i);
- }
- }
-
- read_lock(&tasklist_lock);
- for_each_task(p) {
- if ((tty->session > 0) && (p->session == tty->session) &&
- p->leader) {
- send_sig(SIGHUP,p,1);
- send_sig(SIGCONT,p,1);
- if (tty->pgrp > 0)
- p->tty_old_pgrp = tty->pgrp;
- }
- if (p->tty == tty)
- p->tty = NULL;
- }
- read_unlock(&tasklist_lock);
-
- tty->flags = 0;
- tty->session = 0;
- tty->pgrp = -1;
- tty->ctrl_status = 0;
- /*
- * If one of the devices matches a console pointer, we
- * cannot just call hangup() because that will cause
- * tty->count and state->count to go out of sync.
- * So we just call close() the right number of times.
- */
- if (cons_filp) {
- if (tty->driver.close)
- for (n = 0; n < closecount; n++)
- tty->driver.close(tty, cons_filp);
- } else if (tty->driver.hangup)
- (tty->driver.hangup)(tty);
- unlock_kernel();
-}
-
-void tty_hangup(struct tty_struct * tty)
-{
-#ifdef TTY_DEBUG_HANGUP
- char buf[64];
-
- printk(KERN_DEBUG "%s hangup...\n", tty_name(tty, buf));
-#endif
- schedule_task(&tty->tq_hangup);
-}
-
-void tty_vhangup(struct tty_struct * tty)
-{
-#ifdef TTY_DEBUG_HANGUP
- char buf[64];
-
- printk(KERN_DEBUG "%s vhangup...\n", tty_name(tty, buf));
-#endif
- do_tty_hangup((void *) tty);
-}
-
-int tty_hung_up_p(struct file * filp)
-{
- return (filp->f_op == &hung_up_tty_fops);
-}
-
-/*
- * This function is typically called only by the session leader, when
- * it wants to disassociate itself from its controlling tty.
- *
- * It performs the following functions:
- * (1) Sends a SIGHUP and SIGCONT to the foreground process group
- * (2) Clears the tty from being controlling the session
- * (3) Clears the controlling tty for all processes in the
- * session group.
- *
- * The argument on_exit is set to 1 if called when a process is
- * exiting; it is 0 if called by the ioctl TIOCNOTTY.
- */
-void disassociate_ctty(int on_exit)
-{
- struct tty_struct *tty = current->tty;
- struct task_struct *p;
- int tty_pgrp = -1;
-
- if (tty) {
- tty_pgrp = tty->pgrp;
- if (on_exit && tty->driver.type != TTY_DRIVER_TYPE_PTY)
- tty_vhangup(tty);
- } else {
- if (current->tty_old_pgrp) {
- kill_pg(current->tty_old_pgrp, SIGHUP, on_exit);
- kill_pg(current->tty_old_pgrp, SIGCONT, on_exit);
- }
- return;
- }
- if (tty_pgrp > 0) {
- kill_pg(tty_pgrp, SIGHUP, on_exit);
- if (!on_exit)
- kill_pg(tty_pgrp, SIGCONT, on_exit);
- }
-
- current->tty_old_pgrp = 0;
- tty->session = 0;
- tty->pgrp = -1;
-
- read_lock(&tasklist_lock);
- for_each_task(p)
- if (p->session == current->session)
- p->tty = NULL;
- read_unlock(&tasklist_lock);
-}
-
-void stop_tty(struct tty_struct *tty)
-{
- if (tty->stopped)
- return;
- tty->stopped = 1;
- if (tty->link && tty->link->packet) {
- tty->ctrl_status &= ~TIOCPKT_START;
- tty->ctrl_status |= TIOCPKT_STOP;
- wake_up_interruptible(&tty->link->read_wait);
- }
- if (tty->driver.stop)
- (tty->driver.stop)(tty);
-}
-
-void start_tty(struct tty_struct *tty)
-{
- if (!tty->stopped || tty->flow_stopped)
- return;
- tty->stopped = 0;
- if (tty->link && tty->link->packet) {
- tty->ctrl_status &= ~TIOCPKT_STOP;
- tty->ctrl_status |= TIOCPKT_START;
- wake_up_interruptible(&tty->link->read_wait);
- }
- if (tty->driver.start)
- (tty->driver.start)(tty);
- if ((test_bit(TTY_DO_WRITE_WAKEUP, &tty->flags)) &&
- tty->ldisc.write_wakeup)
- (tty->ldisc.write_wakeup)(tty);
- wake_up_interruptible(&tty->write_wait);
-}
-
-static ssize_t tty_read(struct file * file, char * buf, size_t count,
- loff_t *ppos)
-{
- int i;
- struct tty_struct * tty;
- struct inode *inode;
-
- /* Can't seek (pread) on ttys. */
- if (ppos != &file->f_pos)
- return -ESPIPE;
-
- tty = (struct tty_struct *)file->private_data;
- inode = file->f_dentry->d_inode;
- if (tty_paranoia_check(tty, inode->i_rdev, "tty_read"))
- return -EIO;
- if (!tty || (test_bit(TTY_IO_ERROR, &tty->flags)))
- return -EIO;
-
- /* This check not only needs to be done before reading, but also
- whenever read_chan() gets woken up after sleeping, so I've
- moved it to there. This should only be done for the N_TTY
- line discipline, anyway. Same goes for write_chan(). -- jlc. */
-#if 0
- if ((inode->i_rdev != CONSOLE_DEV) && /* don't stop on /dev/console */
- (tty->pgrp > 0) &&
- (current->tty == tty) &&
- (tty->pgrp != current->pgrp))
- if (is_ignored(SIGTTIN) || is_orphaned_pgrp(current->pgrp))
- return -EIO;
- else {
- (void) kill_pg(current->pgrp, SIGTTIN, 1);
- return -ERESTARTSYS;
- }
-#endif
- lock_kernel();
- if (tty->ldisc.read)
- i = (tty->ldisc.read)(tty,file,buf,count);
- else
- i = -EIO;
- unlock_kernel();
- if (i > 0)
- inode->i_atime = CURRENT_TIME;
- return i;
-}
-
-/*
- * Split writes up in sane blocksizes to avoid
- * denial-of-service type attacks
- */
-static inline ssize_t do_tty_write(
- ssize_t (*write)(struct tty_struct *, struct file *, const unsigned char *, size_t),
- struct tty_struct *tty,
- struct file *file,
- const unsigned char *buf,
- size_t count)
-{
- ssize_t ret = 0, written = 0;
-
- if (file->f_flags & O_NONBLOCK) {
- if (down_trylock(&tty->atomic_write))
- return -EAGAIN;
- }
- else {
- if (down_interruptible(&tty->atomic_write))
- return -ERESTARTSYS;
- }
- if ( test_bit(TTY_NO_WRITE_SPLIT, &tty->flags) ) {
- lock_kernel();
- written = write(tty, file, buf, count);
- unlock_kernel();
- } else {
- for (;;) {
- unsigned long size = MAX(PAGE_SIZE*2,16384);
- if (size > count)
- size = count;
- lock_kernel();
- ret = write(tty, file, buf, size);
- unlock_kernel();
- if (ret <= 0)
- break;
- written += ret;
- buf += ret;
- count -= ret;
- if (!count)
- break;
- ret = -ERESTARTSYS;
- if (signal_pending(current))
- break;
- if (current->need_resched)
- schedule();
- }
- }
- if (written) {
- file->f_dentry->d_inode->i_mtime = CURRENT_TIME;
- ret = written;
- }
- up(&tty->atomic_write);
- return ret;
-}
-
-
-static ssize_t tty_write(struct file * file, const char * buf, size_t count,
- loff_t *ppos)
-{
- int is_console;
- struct tty_struct * tty;
- struct inode *inode;
-
- /* Can't seek (pwrite) on ttys. */
- if (ppos != &file->f_pos)
- return -ESPIPE;
-
- /*
- * For now, we redirect writes from /dev/console as
- * well as /dev/tty0.
- */
- inode = file->f_dentry->d_inode;
- is_console = (inode->i_rdev == SYSCONS_DEV ||
- inode->i_rdev == CONSOLE_DEV);
-
- if (is_console && redirect)
- tty = redirect;
- else
- tty = (struct tty_struct *)file->private_data;
- if (tty_paranoia_check(tty, inode->i_rdev, "tty_write"))
- return -EIO;
- if (!tty || !tty->driver.write || (test_bit(TTY_IO_ERROR, &tty->flags)))
- return -EIO;
-#if 0
- if (!is_console && L_TOSTOP(tty) && (tty->pgrp > 0) &&
- (current->tty == tty) && (tty->pgrp != current->pgrp)) {
- if (is_orphaned_pgrp(current->pgrp))
- return -EIO;
- if (!is_ignored(SIGTTOU)) {
- (void) kill_pg(current->pgrp, SIGTTOU, 1);
- return -ERESTARTSYS;
- }
- }
-#endif
- if (!tty->ldisc.write)
- return -EIO;
- return do_tty_write(tty->ldisc.write, tty, file,
- (const unsigned char *)buf, count);
-}
-
-/* Semaphore to protect creating and releasing a tty */
-static DECLARE_MUTEX(tty_sem);
-
-static void down_tty_sem(int index)
-{
- down(&tty_sem);
-}
-
-static void up_tty_sem(int index)
-{
- up(&tty_sem);
-}
-
-static void release_mem(struct tty_struct *tty, int idx);
-
-/*
- * WSH 06/09/97: Rewritten to remove races and properly clean up after a
- * failed open. The new code protects the open with a semaphore, so it's
- * really quite straightforward. The semaphore locking can probably be
- * relaxed for the (most common) case of reopening a tty.
- */
-static int init_dev(kdev_t device, struct tty_struct **ret_tty)
-{
- struct tty_struct *tty, *o_tty;
- struct termios *tp, **tp_loc, *o_tp, **o_tp_loc;
- struct termios *ltp, **ltp_loc, *o_ltp, **o_ltp_loc;
- struct tty_driver *driver;
- int retval=0;
- int idx;
-
- driver = get_tty_driver(device);
- if (!driver) {
- return -ENODEV;
- }
-
- idx = MINOR(device) - driver->minor_start;
-
- /*
- * Check whether we need to acquire the tty semaphore to avoid
- * race conditions. For now, play it safe.
- */
- down_tty_sem(idx);
-
- /* check whether we're reopening an existing tty */
- tty = driver->table[idx];
- if (tty) goto fast_track;
-
- /*
- * First time open is complex, especially for PTY devices.
- * This code guarantees that either everything succeeds and the
- * TTY is ready for operation, or else the table slots are vacated
- * and the allocated memory released. (Except that the termios
- * and locked termios may be retained.)
- */
-
- o_tty = NULL;
- tp = o_tp = NULL;
- ltp = o_ltp = NULL;
-
- tty = alloc_tty_struct();
- if(!tty)
- goto fail_no_mem;
- initialize_tty_struct(tty);
- tty->device = device;
- tty->driver = *driver;
-
- tp_loc = &driver->termios[idx];
- if (!*tp_loc) {
- tp = (struct termios *) kmalloc(sizeof(struct termios),
- GFP_KERNEL);
- if (!tp)
- goto free_mem_out;
- *tp = driver->init_termios;
- }
-
- ltp_loc = &driver->termios_locked[idx];
- if (!*ltp_loc) {
- ltp = (struct termios *) kmalloc(sizeof(struct termios),
- GFP_KERNEL);
- if (!ltp)
- goto free_mem_out;
- memset(ltp, 0, sizeof(struct termios));
- }
-
- if (driver->type == TTY_DRIVER_TYPE_PTY) {
- o_tty = alloc_tty_struct();
- if (!o_tty)
- goto free_mem_out;
- initialize_tty_struct(o_tty);
- o_tty->device = (kdev_t) MKDEV(driver->other->major,
- driver->other->minor_start + idx);
- o_tty->driver = *driver->other;
-
- o_tp_loc = &driver->other->termios[idx];
- if (!*o_tp_loc) {
- o_tp = (struct termios *)
- kmalloc(sizeof(struct termios), GFP_KERNEL);
- if (!o_tp)
- goto free_mem_out;
- *o_tp = driver->other->init_termios;
- }
-
- o_ltp_loc = &driver->other->termios_locked[idx];
- if (!*o_ltp_loc) {
- o_ltp = (struct termios *)
- kmalloc(sizeof(struct termios), GFP_KERNEL);
- if (!o_ltp)
- goto free_mem_out;
- memset(o_ltp, 0, sizeof(struct termios));
- }
-
- /*
- * Everything allocated ... set up the o_tty structure.
- */
- driver->other->table[idx] = o_tty;
- if (!*o_tp_loc)
- *o_tp_loc = o_tp;
- if (!*o_ltp_loc)
- *o_ltp_loc = o_ltp;
- o_tty->termios = *o_tp_loc;
- o_tty->termios_locked = *o_ltp_loc;
- (*driver->other->refcount)++;
- if (driver->subtype == PTY_TYPE_MASTER)
- o_tty->count++;
-
- /* Establish the links in both directions */
- tty->link = o_tty;
- o_tty->link = tty;
- }
-
- /*
- * All structures have been allocated, so now we install them.
- * Failures after this point use release_mem to clean up, so
- * there's no need to null out the local pointers.
- */
- driver->table[idx] = tty;
-
- if (!*tp_loc)
- *tp_loc = tp;
- if (!*ltp_loc)
- *ltp_loc = ltp;
- tty->termios = *tp_loc;
- tty->termios_locked = *ltp_loc;
- (*driver->refcount)++;
- tty->count++;
-
- /*
- * Structures all installed ... call the ldisc open routines.
- * If we fail here just call release_mem to clean up. No need
- * to decrement the use counts, as release_mem doesn't care.
- */
- if (tty->ldisc.open) {
- retval = (tty->ldisc.open)(tty);
- if (retval)
- goto release_mem_out;
- }
- if (o_tty && o_tty->ldisc.open) {
- retval = (o_tty->ldisc.open)(o_tty);
- if (retval) {
- if (tty->ldisc.close)
- (tty->ldisc.close)(tty);
- goto release_mem_out;
- }
- }
- goto success;
-
- /*
- * This fast open can be used if the tty is already open.
- * No memory is allocated, and the only failures are from
- * attempting to open a closing tty or attempting multiple
- * opens on a pty master.
- */
-fast_track:
- if (test_bit(TTY_CLOSING, &tty->flags)) {
- retval = -EIO;
- goto end_init;
- }
- if (driver->type == TTY_DRIVER_TYPE_PTY &&
- driver->subtype == PTY_TYPE_MASTER) {
- /*
- * special case for PTY masters: only one open permitted,
- * and the slave side open count is incremented as well.
- */
- if (tty->count) {
- retval = -EIO;
- goto end_init;
- }
- tty->link->count++;
- }
- tty->count++;
- tty->driver = *driver; /* N.B. why do this every time?? */
-
-success:
- *ret_tty = tty;
-
- /* All paths come through here to release the semaphore */
-end_init:
- up_tty_sem(idx);
- return retval;
-
- /* Release locally allocated memory ... nothing placed in slots */
-free_mem_out:
- if (o_tp)
- kfree(o_tp);
- if (o_tty)
- free_tty_struct(o_tty);
- if (ltp)
- kfree(ltp);
- if (tp)
- kfree(tp);
- free_tty_struct(tty);
-
-fail_no_mem:
- retval = -ENOMEM;
- goto end_init;
-
- /* call the tty release_mem routine to clean out this slot */
-release_mem_out:
- printk(KERN_INFO "init_dev: ldisc open failed, "
- "clearing slot %d\n", idx);
- release_mem(tty, idx);
- goto end_init;
-}
-
-/*
- * Releases memory associated with a tty structure, and clears out the
- * driver table slots.
- */
-static void release_mem(struct tty_struct *tty, int idx)
-{
- struct tty_struct *o_tty;
- struct termios *tp;
-
- if ((o_tty = tty->link) != NULL) {
- o_tty->driver.table[idx] = NULL;
- if (o_tty->driver.flags & TTY_DRIVER_RESET_TERMIOS) {
- tp = o_tty->driver.termios[idx];
- o_tty->driver.termios[idx] = NULL;
- kfree(tp);
- }
- o_tty->magic = 0;
- (*o_tty->driver.refcount)--;
- list_del(&o_tty->tty_files);
- free_tty_struct(o_tty);
- }
-
- tty->driver.table[idx] = NULL;
- if (tty->driver.flags & TTY_DRIVER_RESET_TERMIOS) {
- tp = tty->driver.termios[idx];
- tty->driver.termios[idx] = NULL;
- kfree(tp);
- }
- tty->magic = 0;
- (*tty->driver.refcount)--;
- list_del(&tty->tty_files);
- free_tty_struct(tty);
-}
-
-/*
- * Even releasing the tty structures is a tricky business.. We have
- * to be very careful that the structures are all released at the
- * same time, as interrupts might otherwise get the wrong pointers.
- *
- * WSH 09/09/97: rewritten to avoid some nasty race conditions that could
- * lead to double frees or releasing memory still in use.
- */
-static void release_dev(struct file * filp)
-{
- struct tty_struct *tty, *o_tty;
- int pty_master, tty_closing, o_tty_closing, do_sleep;
- int idx;
- char buf[64];
-
- tty = (struct tty_struct *)filp->private_data;
- if (tty_paranoia_check(tty, filp->f_dentry->d_inode->i_rdev, "release_dev"))
- return;
-
- check_tty_count(tty, "release_dev");
-
- tty_fasync(-1, filp, 0);
-
- idx = MINOR(tty->device) - tty->driver.minor_start;
- pty_master = (tty->driver.type == TTY_DRIVER_TYPE_PTY &&
- tty->driver.subtype == PTY_TYPE_MASTER);
- o_tty = tty->link;
-
-#ifdef TTY_PARANOIA_CHECK
- if (idx < 0 || idx >= tty->driver.num) {
- printk(KERN_DEBUG "release_dev: bad idx when trying to "
- "free (%s)\n", kdevname(tty->device));
- return;
- }
- if (tty != tty->driver.table[idx]) {
- printk(KERN_DEBUG "release_dev: driver.table[%d] not tty "
- "for (%s)\n", idx, kdevname(tty->device));
- return;
- }
- if (tty->termios != tty->driver.termios[idx]) {
- printk(KERN_DEBUG "release_dev: driver.termios[%d] not termios "
- "for (%s)\n",
- idx, kdevname(tty->device));
- return;
- }
- if (tty->termios_locked != tty->driver.termios_locked[idx]) {
- printk(KERN_DEBUG "release_dev: driver.termios_locked[%d] not "
- "termios_locked for (%s)\n",
- idx, kdevname(tty->device));
- return;
- }
-#endif
-
-#ifdef TTY_DEBUG_HANGUP
- printk(KERN_DEBUG "release_dev of %s (tty count=%d)...",
- tty_name(tty, buf), tty->count);
-#endif
-
-#ifdef TTY_PARANOIA_CHECK
- if (tty->driver.other) {
- if (o_tty != tty->driver.other->table[idx]) {
- printk(KERN_DEBUG "release_dev: other->table[%d] "
- "not o_tty for (%s)\n",
- idx, kdevname(tty->device));
- return;
- }
- if (o_tty->termios != tty->driver.other->termios[idx]) {
- printk(KERN_DEBUG "release_dev: other->termios[%d] "
- "not o_termios for (%s)\n",
- idx, kdevname(tty->device));
- return;
- }
- if (o_tty->termios_locked !=
- tty->driver.other->termios_locked[idx]) {
- printk(KERN_DEBUG "release_dev: other->termios_locked["
- "%d] not o_termios_locked for (%s)\n",
- idx, kdevname(tty->device));
- return;
- }
- if (o_tty->link != tty) {
- printk(KERN_DEBUG "release_dev: bad pty pointers\n");
- return;
- }
- }
-#endif
-
- if (tty->driver.close)
- tty->driver.close(tty, filp);
-
- /*
- * Sanity check: if tty->count is going to zero, there shouldn't be
- * any waiters on tty->read_wait or tty->write_wait. We test the
- * wait queues and kick everyone out _before_ actually starting to
- * close. This ensures that we won't block while releasing the tty
- * structure.
- *
- * The test for the o_tty closing is necessary, since the master and
- * slave sides may close in any order. If the slave side closes out
- * first, its count will be one, since the master side holds an open.
- * Thus this test wouldn't be triggered at the time the slave closes,
- * so we do it now.
- *
- * Note that it's possible for the tty to be opened again while we're
- * flushing out waiters. By recalculating the closing flags before
- * each iteration we avoid any problems.
- */
- while (1) {
- tty_closing = tty->count <= 1;
- o_tty_closing = o_tty &&
- (o_tty->count <= (pty_master ? 1 : 0));
- do_sleep = 0;
-
- if (tty_closing) {
- if (waitqueue_active(&tty->read_wait)) {
- wake_up(&tty->read_wait);
- do_sleep++;
- }
- if (waitqueue_active(&tty->write_wait)) {
- wake_up(&tty->write_wait);
- do_sleep++;
- }
- }
- if (o_tty_closing) {
- if (waitqueue_active(&o_tty->read_wait)) {
- wake_up(&o_tty->read_wait);
- do_sleep++;
- }
- if (waitqueue_active(&o_tty->write_wait)) {
- wake_up(&o_tty->write_wait);
- do_sleep++;
- }
- }
- if (!do_sleep)
- break;
-
- printk(KERN_WARNING "release_dev: %s: read/write wait queue "
- "active!\n", tty_name(tty, buf));
- schedule();
- }
-
- /*
- * The closing flags are now consistent with the open counts on
- * both sides, and we've completed the last operation that could
- * block, so it's safe to proceed with closing.
- */
- if (pty_master) {
- if (--o_tty->count < 0) {
- printk(KERN_WARNING "release_dev: bad pty slave count "
- "(%d) for %s\n",
- o_tty->count, tty_name(o_tty, buf));
- o_tty->count = 0;
- }
- }
- if (--tty->count < 0) {
- printk(KERN_WARNING "release_dev: bad tty->count (%d) for %s\n",
- tty->count, tty_name(tty, buf));
- tty->count = 0;
- }
-
- /*
- * We've decremented tty->count, so we should zero out
- * filp->private_data, to break the link between the tty and
- * the file descriptor. Otherwise if filp_close() blocks before
- * the file descriptor is removed from the inuse_filp
- * list, check_tty_count() could observe a discrepancy and
- * printk a warning message to the user.
- */
- filp->private_data = 0;
-
- /*
- * Perform some housekeeping before deciding whether to return.
- *
- * Set the TTY_CLOSING flag if this was the last open. In the
- * case of a pty we may have to wait around for the other side
- * to close, and TTY_CLOSING makes sure we can't be reopened.
- */
- if(tty_closing)
- set_bit(TTY_CLOSING, &tty->flags);
- if(o_tty_closing)
- set_bit(TTY_CLOSING, &o_tty->flags);
-
- /*
- * If _either_ side is closing, make sure there aren't any
- * processes that still think tty or o_tty is their controlling
- * tty. Also, clear redirect if it points to either tty.
- */
- if (tty_closing || o_tty_closing) {
- struct task_struct *p;
-
- read_lock(&tasklist_lock);
- for_each_task(p) {
- if (p->tty == tty || (o_tty && p->tty == o_tty))
- p->tty = NULL;
- }
- read_unlock(&tasklist_lock);
-
- if (redirect == tty || (o_tty && redirect == o_tty))
- redirect = NULL;
- }
-
- /* check whether both sides are closing ... */
- if (!tty_closing || (o_tty && !o_tty_closing))
- return;
-
-#ifdef TTY_DEBUG_HANGUP
- printk(KERN_DEBUG "freeing tty structure...");
-#endif
-
- /*
- * Shutdown the current line discipline, and reset it to N_TTY.
- * N.B. why reset ldisc when we're releasing the memory??
- */
- if (tty->ldisc.close)
- (tty->ldisc.close)(tty);
- tty->ldisc = ldiscs[N_TTY];
- tty->termios->c_line = N_TTY;
- if (o_tty) {
- if (o_tty->ldisc.close)
- (o_tty->ldisc.close)(o_tty);
- o_tty->ldisc = ldiscs[N_TTY];
- }
-
- /*
- * Make sure that the tty's task queue isn't activated.
- */
- run_task_queue(&tq_timer);
- flush_scheduled_tasks();
-
- /*
- * The release_mem function takes care of the details of clearing
- * the slots and preserving the termios structure.
- */
- release_mem(tty, idx);
-}
-
-/*
- * tty_open and tty_release keep up the tty count that contains the
- * number of opens done on a tty. We cannot use the inode-count, as
- * different inodes might point to the same tty.
- *
- * Open-counting is needed for pty masters, as well as for keeping
- * track of serial lines: DTR is dropped when the last close happens.
- * (This is not done solely through tty->count, now. - Ted 1/27/92)
- *
- * The termios state of a pty is reset on first open so that
- * settings don't persist across reuse.
- */
-static int tty_open(struct inode * inode, struct file * filp)
-{
- struct tty_struct *tty;
- int noctty, retval;
- kdev_t device;
- unsigned short saved_flags;
- char buf[64];
-
- saved_flags = filp->f_flags;
-retry_open:
- noctty = filp->f_flags & O_NOCTTY;
- device = inode->i_rdev;
- if (device == TTY_DEV) {
- if (!current->tty)
- return -ENXIO;
- device = current->tty->device;
- filp->f_flags |= O_NONBLOCK; /* Don't let /dev/tty block */
- /* noctty = 1; */
- }
-#ifdef CONFIG_VT
- if (device == CONSOLE_DEV) {
- extern int fg_console;
- device = MKDEV(TTY_MAJOR, fg_console + 1);
- noctty = 1;
- }
-#endif
- if (device == SYSCONS_DEV) {
- struct console *c = console_drivers;
- while(c && !c->device)
- c = c->next;
- if (!c)
- return -ENODEV;
- device = c->device(c);
- filp->f_flags |= O_NONBLOCK; /* Don't let /dev/console block */
- noctty = 1;
- }
-
- if (device == PTMX_DEV) {
-#ifdef CONFIG_UNIX98_PTYS
-
- /* find a free pty. */
- int major, minor;
- struct tty_driver *driver;
-
- /* find a device that is not in use. */
- retval = -1;
- for ( major = 0 ; major < UNIX98_NR_MAJORS ; major++ ) {
- driver = &ptm_driver[major];
- for (minor = driver->minor_start ;
- minor < driver->minor_start + driver->num ;
- minor++) {
- device = MKDEV(driver->major, minor);
- if (!init_dev(device, &tty)) goto ptmx_found; /* ok! */
- }
- }
- return -EIO; /* no free ptys */
- ptmx_found:
- set_bit(TTY_PTY_LOCK, &tty->flags); /* LOCK THE SLAVE */
- minor -= driver->minor_start;
- devpts_pty_new(driver->other->name_base + minor, MKDEV(driver->other->major, minor + driver->other->minor_start));
- tty_register_devfs(&pts_driver[major], DEVFS_FL_DEFAULT,
- pts_driver[major].minor_start + minor);
- noctty = 1;
- goto init_dev_done;
-
-#else /* CONFIG_UNIX_98_PTYS */
-
- return -ENODEV;
-
-#endif /* CONFIG_UNIX_98_PTYS */
- }
-
- retval = init_dev(device, &tty);
- if (retval)
- return retval;
-
-#ifdef CONFIG_UNIX98_PTYS
-init_dev_done:
-#endif
- filp->private_data = tty;
- file_move(filp, &tty->tty_files);
- check_tty_count(tty, "tty_open");
- if (tty->driver.type == TTY_DRIVER_TYPE_PTY &&
- tty->driver.subtype == PTY_TYPE_MASTER)
- noctty = 1;
-#ifdef TTY_DEBUG_HANGUP
- printk(KERN_DEBUG "opening %s...", tty_name(tty, buf));
-#endif
- if (tty->driver.open)
- retval = tty->driver.open(tty, filp);
- else
- retval = -ENODEV;
- filp->f_flags = saved_flags;
-
- if (!retval && test_bit(TTY_EXCLUSIVE, &tty->flags) && !suser())
- retval = -EBUSY;
-
- if (retval) {
-#ifdef TTY_DEBUG_HANGUP
- printk(KERN_DEBUG "error %d in opening %s...", retval,
- tty_name(tty, buf));
-#endif
-
- release_dev(filp);
- if (retval != -ERESTARTSYS)
- return retval;
- if (signal_pending(current))
- return retval;
- schedule();
- /*
- * Need to reset f_op in case a hangup happened.
- */
- filp->f_op = &tty_fops;
- goto retry_open;
- }
- if (!noctty &&
- current->leader &&
- !current->tty &&
- tty->session == 0) {
- task_lock(current);
- current->tty = tty;
- task_unlock(current);
- current->tty_old_pgrp = 0;
- tty->session = current->session;
- tty->pgrp = current->pgrp;
- }
- if ((tty->driver.type == TTY_DRIVER_TYPE_SERIAL) &&
- (tty->driver.subtype == SERIAL_TYPE_CALLOUT) &&
- (tty->count == 1)) {
- static int nr_warns;
- if (nr_warns < 5) {
- printk(KERN_WARNING "tty_io.c: "
- "process %d (%s) used obsolete /dev/%s - "
- "update software to use /dev/ttyS%d\n",
- current->pid, current->comm,
- tty_name(tty, buf), TTY_NUMBER(tty));
- nr_warns++;
- }
- }
- return 0;
-}
-
-static int tty_release(struct inode * inode, struct file * filp)
-{
- lock_kernel();
- release_dev(filp);
- unlock_kernel();
- return 0;
-}
-
-/* No kernel lock held - fine */
-static unsigned int tty_poll(struct file * filp, poll_table * wait)
-{
- struct tty_struct * tty;
-
- tty = (struct tty_struct *)filp->private_data;
- if (tty_paranoia_check(tty, filp->f_dentry->d_inode->i_rdev, "tty_poll"))
- return 0;
-
- if (tty->ldisc.poll)
- return (tty->ldisc.poll)(tty, filp, wait);
- return 0;
-}
-
-static int tty_fasync(int fd, struct file * filp, int on)
-{
- struct tty_struct * tty;
- int retval;
-
- tty = (struct tty_struct *)filp->private_data;
- if (tty_paranoia_check(tty, filp->f_dentry->d_inode->i_rdev, "tty_fasync"))
- return 0;
-
- retval = fasync_helper(fd, filp, on, &tty->fasync);
- if (retval <= 0)
- return retval;
-
- if (on) {
- if (!waitqueue_active(&tty->read_wait))
- tty->minimum_to_wake = 1;
- if (filp->f_owner.pid == 0) {
- filp->f_owner.pid = (-tty->pgrp) ? : current->pid;
- filp->f_owner.uid = current->uid;
- filp->f_owner.euid = current->euid;
- }
- } else {
- if (!tty->fasync && !waitqueue_active(&tty->read_wait))
- tty->minimum_to_wake = N_TTY_BUF_SIZE;
- }
- return 0;
-}
-
-static int tiocsti(struct tty_struct *tty, char * arg)
-{
- char ch, mbz = 0;
-
- if ((current->tty != tty) && !suser())
- return -EPERM;
- if (get_user(ch, arg))
- return -EFAULT;
- tty->ldisc.receive_buf(tty, &ch, &mbz, 1);
- return 0;
-}
-
-static int tiocgwinsz(struct tty_struct *tty, struct winsize * arg)
-{
- if (copy_to_user(arg, &tty->winsize, sizeof(*arg)))
- return -EFAULT;
- return 0;
-}
-
-static int tiocswinsz(struct tty_struct *tty, struct tty_struct *real_tty,
- struct winsize * arg)
-{
- struct winsize tmp_ws;
-
- if (copy_from_user(&tmp_ws, arg, sizeof(*arg)))
- return -EFAULT;
- if (!memcmp(&tmp_ws, &tty->winsize, sizeof(*arg)))
- return 0;
- if (tty->pgrp > 0)
- kill_pg(tty->pgrp, SIGWINCH, 1);
- if ((real_tty->pgrp != tty->pgrp) && (real_tty->pgrp > 0))
- kill_pg(real_tty->pgrp, SIGWINCH, 1);
- tty->winsize = tmp_ws;
- real_tty->winsize = tmp_ws;
- return 0;
-}
-
-static int tioccons(struct inode *inode,
- struct tty_struct *tty, struct tty_struct *real_tty)
-{
- if (inode->i_rdev == SYSCONS_DEV ||
- inode->i_rdev == CONSOLE_DEV) {
- if (!suser())
- return -EPERM;
- redirect = NULL;
- return 0;
- }
- if (redirect)
- return -EBUSY;
- redirect = real_tty;
- return 0;
-}
-
-
-static int fionbio(struct file *file, int *arg)
-{
- int nonblock;
-
- if (get_user(nonblock, arg))
- return -EFAULT;
-
- if (nonblock)
- file->f_flags |= O_NONBLOCK;
- else
- file->f_flags &= ~O_NONBLOCK;
- return 0;
-}
-
-static int tiocsctty(struct tty_struct *tty, int arg)
-{
- if (current->leader &&
- (current->session == tty->session))
- return 0;
- /*
- * The process must be a session leader and
- * not have a controlling tty already.
- */
- if (!current->leader || current->tty)
- return -EPERM;
- if (tty->session > 0) {
- /*
- * This tty is already the controlling
- * tty for another session group!
- */
- if ((arg == 1) && suser()) {
- /*
- * Steal it away
- */
- struct task_struct *p;
-
- read_lock(&tasklist_lock);
- for_each_task(p)
- if (p->tty == tty)
- p->tty = NULL;
- read_unlock(&tasklist_lock);
- } else
- return -EPERM;
- }
- task_lock(current);
- current->tty = tty;
- task_unlock(current);
- current->tty_old_pgrp = 0;
- tty->session = current->session;
- tty->pgrp = current->pgrp;
- return 0;
-}
-
-static int tiocgpgrp(struct tty_struct *tty, struct tty_struct *real_tty, pid_t *arg)
-{
- /*
- * (tty == real_tty) is a cheap way of
- * testing if the tty is NOT a master pty.
- */
- if (tty == real_tty && current->tty != real_tty)
- return -ENOTTY;
- return put_user(real_tty->pgrp, arg);
-}
-
-static int tiocspgrp(struct tty_struct *tty, struct tty_struct *real_tty, pid_t *arg)
-{
- pid_t pgrp;
- int retval = tty_check_change(real_tty);
-
- if (retval == -EIO)
- return -ENOTTY;
- if (retval)
- return retval;
- if (!current->tty ||
- (current->tty != real_tty) ||
- (real_tty->session != current->session))
- return -ENOTTY;
- if (get_user(pgrp, (pid_t *) arg))
- return -EFAULT;
- if (pgrp < 0)
- return -EINVAL;
- if (session_of_pgrp(pgrp) != current->session)
- return -EPERM;
- real_tty->pgrp = pgrp;
- return 0;
-}
-
-static int tiocgsid(struct tty_struct *tty, struct tty_struct *real_tty, pid_t *arg)
-{
- /*
- * (tty == real_tty) is a cheap way of
- * testing if the tty is NOT a master pty.
- */
- if (tty == real_tty && current->tty != real_tty)
- return -ENOTTY;
- if (real_tty->session <= 0)
- return -ENOTTY;
- return put_user(real_tty->session, arg);
-}
-
-static int tiocttygstruct(struct tty_struct *tty, struct tty_struct *arg)
-{
- if (copy_to_user(arg, tty, sizeof(*arg)))
- return -EFAULT;
- return 0;
-}
-
-static int tiocsetd(struct tty_struct *tty, int *arg)
-{
- int ldisc;
-
- if (get_user(ldisc, arg))
- return -EFAULT;
- return tty_set_ldisc(tty, ldisc);
-}
-
-static int send_break(struct tty_struct *tty, int duration)
-{
- set_current_state(TASK_INTERRUPTIBLE);
-
- tty->driver.break_ctl(tty, -1);
- if (!signal_pending(current))
- schedule_timeout(duration);
- tty->driver.break_ctl(tty, 0);
- if (signal_pending(current))
- return -EINTR;
- return 0;
-}
-
-static int tty_generic_brk(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg)
-{
- if (cmd == TCSBRK && arg)
- {
- /* tcdrain case */
- int retval = tty_check_change(tty);
- if (retval)
- return retval;
- tty_wait_until_sent(tty, 0);
- if (signal_pending(current))
- return -EINTR;
- }
- return 0;
-}
-
-/*
- * Split this up, as gcc can choke on it otherwise..
- */
-int tty_ioctl(struct inode * inode, struct file * file,
- unsigned int cmd, unsigned long arg)
-{
- struct tty_struct *tty, *real_tty;
- int retval;
-
- tty = (struct tty_struct *)file->private_data;
- if (tty_paranoia_check(tty, inode->i_rdev, "tty_ioctl"))
- return -EINVAL;
-
- real_tty = tty;
- if (tty->driver.type == TTY_DRIVER_TYPE_PTY &&
- tty->driver.subtype == PTY_TYPE_MASTER)
- real_tty = tty->link;
-
- /*
- * Break handling by driver
- */
- if (!tty->driver.break_ctl) {
- switch(cmd) {
- case TIOCSBRK:
- case TIOCCBRK:
- if (tty->driver.ioctl)
- return tty->driver.ioctl(tty, file, cmd, arg);
- return -EINVAL;
-
- /* These two ioctl's always return success; even if */
- /* the driver doesn't support them. */
- case TCSBRK:
- case TCSBRKP:
- retval = -ENOIOCTLCMD;
- if (tty->driver.ioctl)
- retval = tty->driver.ioctl(tty, file, cmd, arg);
- /* Not driver handled */
- if (retval == -ENOIOCTLCMD)
- retval = tty_generic_brk(tty, file, cmd, arg);
- return retval;
- }
- }
-
- /*
- * Factor out some common prep work
- */
- switch (cmd) {
- case TIOCSETD:
- case TIOCSBRK:
- case TIOCCBRK:
- case TCSBRK:
- case TCSBRKP:
- retval = tty_check_change(tty);
- if (retval)
- return retval;
- if (cmd != TIOCCBRK) {
- tty_wait_until_sent(tty, 0);
- if (signal_pending(current))
- return -EINTR;
- }
- break;
- }
-
- switch (cmd) {
- case TIOCSTI:
- return tiocsti(tty, (char *)arg);
- case TIOCGWINSZ:
- return tiocgwinsz(tty, (struct winsize *) arg);
- case TIOCSWINSZ:
- return tiocswinsz(tty, real_tty, (struct winsize *) arg);
- case TIOCCONS:
- return tioccons(inode, tty, real_tty);
- case FIONBIO:
- return fionbio(file, (int *) arg);
- case TIOCEXCL:
- set_bit(TTY_EXCLUSIVE, &tty->flags);
- return 0;
- case TIOCNXCL:
- clear_bit(TTY_EXCLUSIVE, &tty->flags);
- return 0;
- case TIOCNOTTY:
- if (current->tty != tty)
- return -ENOTTY;
- if (current->leader)
- disassociate_ctty(0);
- task_lock(current);
- current->tty = NULL;
- task_unlock(current);
- return 0;
- case TIOCSCTTY:
- return tiocsctty(tty, arg);
- case TIOCGPGRP:
- return tiocgpgrp(tty, real_tty, (pid_t *) arg);
- case TIOCSPGRP:
- return tiocspgrp(tty, real_tty, (pid_t *) arg);
- case TIOCGSID:
- return tiocgsid(tty, real_tty, (pid_t *) arg);
- case TIOCGETD:
- return put_user(tty->ldisc.num, (int *) arg);
- case TIOCSETD:
- return tiocsetd(tty, (int *) arg);
-#ifdef CONFIG_VT
- case TIOCLINUX:
- return tioclinux(tty, arg);
-#endif
- case TIOCTTYGSTRUCT:
- return tiocttygstruct(tty, (struct tty_struct *) arg);
-
- /*
- * Break handling
- */
- case TIOCSBRK: /* Turn break on, unconditionally */
- tty->driver.break_ctl(tty, -1);
- return 0;
-
- case TIOCCBRK: /* Turn break off, unconditionally */
- tty->driver.break_ctl(tty, 0);
- return 0;
- case TCSBRK: /* SVID version: non-zero arg --> no break */
- /*
- * XXX is the above comment correct, or the
- * code below correct? Is this ioctl used at
- * all by anyone?
- */
- if (!arg)
- return send_break(tty, HZ/4);
- return 0;
- case TCSBRKP: /* support for POSIX tcsendbreak() */
- return send_break(tty, arg ? arg*(HZ/10) : HZ/4);
- }
- if (tty->driver.ioctl) {
- int retval = (tty->driver.ioctl)(tty, file, cmd, arg);
- if (retval != -ENOIOCTLCMD)
- return retval;
- }
- if (tty->ldisc.ioctl) {
- int retval = (tty->ldisc.ioctl)(tty, file, cmd, arg);
- if (retval != -ENOIOCTLCMD)
- return retval;
- }
- return -EINVAL;
-}
-
-
-/*
- * This implements the "Secure Attention Key" --- the idea is to
- * prevent trojan horses by killing all processes associated with this
- * tty when the user hits the "Secure Attention Key". Required for
- * super-paranoid applications --- see the Orange Book for more details.
- *
- * This code could be nicer; ideally it should send a HUP, wait a few
- * seconds, then send a INT, and then a KILL signal. But you then
- * have to coordinate with the init process, since all processes associated
- * with the current tty must be dead before the new getty is allowed
- * to spawn.
- *
- * Now, if it would be correct ;-/ The current code has a nasty hole -
- * it doesn't catch files in flight. We may send the descriptor to ourselves
- * via AF_UNIX socket, close it and later fetch from socket. FIXME.
- *
- * Nasty bug: do_SAK is being called in interrupt context. This can
- * deadlock. We punt it up to process context. AKPM - 16Mar2001
- */
-static void __do_SAK(void *arg)
-{
-#ifdef TTY_SOFT_SAK
- tty_hangup(tty);
-#else
- struct tty_struct *tty = arg;
- struct task_struct *p;
- int session;
- int i;
- struct file *filp;
-
- if (!tty)
- return;
- session = tty->session;
- if (tty->ldisc.flush_buffer)
- tty->ldisc.flush_buffer(tty);
- if (tty->driver.flush_buffer)
- tty->driver.flush_buffer(tty);
- read_lock(&tasklist_lock);
- for_each_task(p) {
- if ((p->tty == tty) ||
- ((session > 0) && (p->session == session))) {
- send_sig(SIGKILL, p, 1);
- continue;
- }
- task_lock(p);
- if (p->files) {
- read_lock(&p->files->file_lock);
- for (i=0; i < p->files->max_fds; i++) {
- filp = fcheck_files(p->files, i);
- if (filp && (filp->f_op == &tty_fops) &&
- (filp->private_data == tty)) {
- send_sig(SIGKILL, p, 1);
- break;
- }
- }
- read_unlock(&p->files->file_lock);
- }
- task_unlock(p);
- }
- read_unlock(&tasklist_lock);
-#endif
-}
-
-/*
- * The tq handling here is a little racy - tty->SAK_tq may already be queued.
- * But there's no mechanism to fix that without futzing with tqueue_lock.
- * Fortunately we don't need to worry, because if ->SAK_tq is already queued,
- * the values which we write to it will be identical to the values which it
- * already has. --akpm
- */
-void do_SAK(struct tty_struct *tty)
-{
- if (!tty)
- return;
- PREPARE_TQUEUE(&tty->SAK_tq, __do_SAK, tty);
- schedule_task(&tty->SAK_tq);
-}
-
-/*
- * This routine is called out of the software interrupt to flush data
- * from the flip buffer to the line discipline.
- */
-static void flush_to_ldisc(void *private_)
-{
- struct tty_struct *tty = (struct tty_struct *) private_;
- unsigned char *cp;
- char *fp;
- int count;
- unsigned long flags;
-
- if (test_bit(TTY_DONT_FLIP, &tty->flags)) {
- queue_task(&tty->flip.tqueue, &tq_timer);
- return;
- }
- if (tty->flip.buf_num) {
- cp = tty->flip.char_buf + TTY_FLIPBUF_SIZE;
- fp = tty->flip.flag_buf + TTY_FLIPBUF_SIZE;
- tty->flip.buf_num = 0;
-
- save_flags(flags); cli();
- tty->flip.char_buf_ptr = tty->flip.char_buf;
- tty->flip.flag_buf_ptr = tty->flip.flag_buf;
- } else {
- cp = tty->flip.char_buf;
- fp = tty->flip.flag_buf;
- tty->flip.buf_num = 1;
-
- save_flags(flags); cli();
- tty->flip.char_buf_ptr = tty->flip.char_buf + TTY_FLIPBUF_SIZE;
- tty->flip.flag_buf_ptr = tty->flip.flag_buf + TTY_FLIPBUF_SIZE;
- }
- count = tty->flip.count;
- tty->flip.count = 0;
- restore_flags(flags);
-
- tty->ldisc.receive_buf(tty, cp, fp, count);
-}
-
-/*
- * Routine which returns the baud rate of the tty
- *
- * Note that the baud_table needs to be kept in sync with the
- * include/asm/termbits.h file.
- */
-static int baud_table[] = {
- 0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800,
- 9600, 19200, 38400, 57600, 115200, 230400, 460800,
-#ifdef __sparc__
- 76800, 153600, 307200, 614400, 921600
-#else
- 500000, 576000, 921600, 1000000, 1152000, 1500000, 2000000,
- 2500000, 3000000, 3500000, 4000000
-#endif
-};
-
-static int n_baud_table = sizeof(baud_table)/sizeof(int);
-
-int tty_get_baud_rate(struct tty_struct *tty)
-{
- unsigned int cflag, i;
-
- cflag = tty->termios->c_cflag;
-
- i = cflag & CBAUD;
- if (i & CBAUDEX) {
- i &= ~CBAUDEX;
- if (i < 1 || i+15 >= n_baud_table)
- tty->termios->c_cflag &= ~CBAUDEX;
- else
- i += 15;
- }
- if (i==15 && tty->alt_speed) {
- if (!tty->warned) {
- printk(KERN_WARNING "Use of setserial/setrocket to "
- "set SPD_* flags is deprecated\n");
- tty->warned = 1;
- }
- return(tty->alt_speed);
- }
-
- return baud_table[i];
-}
-
-void tty_flip_buffer_push(struct tty_struct *tty)
-{
- if (tty->low_latency)
- flush_to_ldisc((void *) tty);
- else
- queue_task(&tty->flip.tqueue, &tq_timer);
-}
-
-/*
- * This subroutine initializes a tty structure.
- */
-static void initialize_tty_struct(struct tty_struct *tty)
-{
- memset(tty, 0, sizeof(struct tty_struct));
- tty->magic = TTY_MAGIC;
- tty->ldisc = ldiscs[N_TTY];
- tty->pgrp = -1;
- tty->flip.char_buf_ptr = tty->flip.char_buf;
- tty->flip.flag_buf_ptr = tty->flip.flag_buf;
- tty->flip.tqueue.routine = flush_to_ldisc;
- tty->flip.tqueue.data = tty;
- init_MUTEX(&tty->flip.pty_sem);
- init_waitqueue_head(&tty->write_wait);
- init_waitqueue_head(&tty->read_wait);
- tty->tq_hangup.routine = do_tty_hangup;
- tty->tq_hangup.data = tty;
- sema_init(&tty->atomic_read, 1);
- sema_init(&tty->atomic_write, 1);
- spin_lock_init(&tty->read_lock);
- INIT_LIST_HEAD(&tty->tty_files);
- INIT_TQUEUE(&tty->SAK_tq, 0, 0);
-}
-
-/*
- * The default put_char routine if the driver did not define one.
- */
-void tty_default_put_char(struct tty_struct *tty, unsigned char ch)
-{
- tty->driver.write(tty, 0, &ch, 1);
-}
-
-/*
- * Register a tty device described by <driver>, with minor number <minor>.
- */
-void tty_register_devfs (struct tty_driver *driver, unsigned int flags, unsigned minor)
-{
-#ifdef CONFIG_DEVFS_FS
- umode_t mode = S_IFCHR | S_IRUSR | S_IWUSR;
- kdev_t device = MKDEV (driver->major, minor);
- int idx = minor - driver->minor_start;
- char buf[32];
-
- switch (device) {
- case TTY_DEV:
- case PTMX_DEV:
- mode |= S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;
- break;
- default:
- if (driver->major == PTY_MASTER_MAJOR)
- mode |= S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;
- break;
- }
- if ( (minor < driver->minor_start) ||
- (minor >= driver->minor_start + driver->num) ) {
- printk(KERN_ERR "Attempt to register invalid minor number "
- "with devfs (%d:%d).\n", (int)driver->major,(int)minor);
- return;
- }
-# ifdef CONFIG_UNIX98_PTYS
- if ( (driver->major >= UNIX98_PTY_SLAVE_MAJOR) &&
- (driver->major < UNIX98_PTY_SLAVE_MAJOR + UNIX98_NR_MAJORS) )
- flags |= DEVFS_FL_CURRENT_OWNER;
-# endif
- sprintf(buf, driver->name, idx + driver->name_base);
- devfs_register (NULL, buf, flags | DEVFS_FL_DEFAULT,
- driver->major, minor, mode, &tty_fops, NULL);
-#endif /* CONFIG_DEVFS_FS */
-}
-
-void tty_unregister_devfs (struct tty_driver *driver, unsigned minor)
-{
-#ifdef CONFIG_DEVFS_FS
- void * handle;
- int idx = minor - driver->minor_start;
- char buf[32];
-
- sprintf(buf, driver->name, idx + driver->name_base);
- handle = devfs_find_handle (NULL, buf, driver->major, minor,
- DEVFS_SPECIAL_CHR, 0);
- devfs_unregister (handle);
-#endif /* CONFIG_DEVFS_FS */
-}
-
-EXPORT_SYMBOL(tty_register_devfs);
-EXPORT_SYMBOL(tty_unregister_devfs);
-
-/*
- * Called by a tty driver to register itself.
- */
-int tty_register_driver(struct tty_driver *driver)
-{
- int error;
- int i;
-
- if (driver->flags & TTY_DRIVER_INSTALLED)
- return 0;
-
- error = devfs_register_chrdev(driver->major, driver->name, &tty_fops);
- if (error < 0)
- return error;
- else if(driver->major == 0)
- driver->major = error;
-
- if (!driver->put_char)
- driver->put_char = tty_default_put_char;
-
- driver->prev = 0;
- driver->next = tty_drivers;
- if (tty_drivers) tty_drivers->prev = driver;
- tty_drivers = driver;
-
- if ( !(driver->flags & TTY_DRIVER_NO_DEVFS) ) {
- for(i = 0; i < driver->num; i++)
- tty_register_devfs(driver, 0, driver->minor_start + i);
- }
- proc_tty_register_driver(driver);
- return error;
-}
-
-/*
- * Called by a tty driver to unregister itself.
- */
-int tty_unregister_driver(struct tty_driver *driver)
-{
- int retval;
- struct tty_driver *p;
- int i, found = 0;
- struct termios *tp;
- const char *othername = NULL;
-
- if (*driver->refcount)
- return -EBUSY;
-
- for (p = tty_drivers; p; p = p->next) {
- if (p == driver)
- found++;
- else if (p->major == driver->major)
- othername = p->name;
- }
-
- if (!found)
- return -ENOENT;
-
- if (othername == NULL) {
- retval = devfs_unregister_chrdev(driver->major, driver->name);
- if (retval)
- return retval;
- } else
- devfs_register_chrdev(driver->major, othername, &tty_fops);
-
- if (driver->prev)
- driver->prev->next = driver->next;
- else
- tty_drivers = driver->next;
-
- if (driver->next)
- driver->next->prev = driver->prev;
-
- /*
- * Free the termios and termios_locked structures because
- * we don't want to get memory leaks when modular tty
- * drivers are removed from the kernel.
- */
- for (i = 0; i < driver->num; i++) {
- tp = driver->termios[i];
- if (tp) {
- driver->termios[i] = NULL;
- kfree(tp);
- }
- tp = driver->termios_locked[i];
- if (tp) {
- driver->termios_locked[i] = NULL;
- kfree(tp);
- }
- tty_unregister_devfs(driver, driver->minor_start + i);
- }
- proc_tty_unregister_driver(driver);
- return 0;
-}
-
-
-/*
- * Initialize the console device. This is called *early*, so
- * we can't necessarily depend on lots of kernel help here.
- * Just do some early initializations, and do the complex setup
- * later.
- */
-void __init console_init(void)
-{
- /* Setup the default TTY line discipline. */
- memset(ldiscs, 0, sizeof(ldiscs));
- (void) tty_register_ldisc(N_TTY, &tty_ldisc_N_TTY);
-
- /*
- * Set up the standard termios. Individual tty drivers may
- * deviate from this; this is used as a template.
- */
- memset(&tty_std_termios, 0, sizeof(struct termios));
- memcpy(tty_std_termios.c_cc, INIT_C_CC, NCCS);
- tty_std_termios.c_iflag = ICRNL | IXON;
- tty_std_termios.c_oflag = OPOST | ONLCR;
- tty_std_termios.c_cflag = B38400 | CS8 | CREAD | HUPCL;
- tty_std_termios.c_lflag = ISIG | ICANON | ECHO | ECHOE | ECHOK |
- ECHOCTL | ECHOKE | IEXTEN;
-
- /*
- * set up the console device so that later boot sequences can
- * inform about problems etc..
- */
-#ifdef CONFIG_EARLY_PRINTK
- disable_early_printk();
-#endif
-
-#ifdef CONFIG_VT
- con_init();
-#endif
-
-#ifdef CONFIG_XEN_CONSOLE
- xen_console_init();
-#endif
-#ifdef CONFIG_AU1000_SERIAL_CONSOLE
- au1000_serial_console_init();
-#endif
-#ifdef CONFIG_SERIAL_CONSOLE
-#if (defined(CONFIG_8xx) || defined(CONFIG_8260))
- console_8xx_init();
-#elif defined(CONFIG_MAC_SERIAL) && defined(CONFIG_SERIAL)
- if (_machine == _MACH_Pmac)
- mac_scc_console_init();
- else
- serial_console_init();
-#elif defined(CONFIG_MAC_SERIAL)
- mac_scc_console_init();
-#elif defined(CONFIG_PARISC)
- pdc_console_init();
-#elif defined(CONFIG_SERIAL)
- serial_console_init();
-#endif /* CONFIG_8xx */
-#ifdef CONFIG_SGI_SERIAL
- sgi_serial_console_init();
-#endif
-#if defined(CONFIG_MVME162_SCC) || defined(CONFIG_BVME6000_SCC) || defined(CONFIG_MVME147_SCC)
- vme_scc_console_init();
-#endif
-#if defined(CONFIG_SERIAL167)
- serial167_console_init();
-#endif
-#if defined(CONFIG_SH_SCI)
- sci_console_init();
-#endif
-#endif
-#ifdef CONFIG_TN3270_CONSOLE
- tub3270_con_init();
-#endif
-#ifdef CONFIG_TN3215
- con3215_init();
-#endif
-#ifdef CONFIG_HWC
- hwc_console_init();
-#endif
-#ifdef CONFIG_STDIO_CONSOLE
- stdio_console_init();
-#endif
-#ifdef CONFIG_SERIAL_21285_CONSOLE
- rs285_console_init();
-#endif
-#ifdef CONFIG_SERIAL_SA1100_CONSOLE
- sa1100_rs_console_init();
-#endif
-#ifdef CONFIG_ARC_CONSOLE
- arc_console_init();
-#endif
-#ifdef CONFIG_SERIAL_AMBA_CONSOLE
- ambauart_console_init();
-#endif
-#ifdef CONFIG_SERIAL_TX3912_CONSOLE
- tx3912_console_init();
-#endif
-#ifdef CONFIG_TXX927_SERIAL_CONSOLE
- txx927_console_init();
-#endif
-#ifdef CONFIG_SIBYTE_SB1250_DUART_CONSOLE
- sb1250_serial_console_init();
-#endif
-}
-
-static struct tty_driver dev_tty_driver, dev_syscons_driver;
-#ifdef CONFIG_UNIX98_PTYS
-static struct tty_driver dev_ptmx_driver;
-#endif
-#ifdef CONFIG_VT
-static struct tty_driver dev_console_driver;
-#endif
-
-/*
- * Ok, now we can initialize the rest of the tty devices and can count
- * on memory allocations, interrupts etc..
- */
-void __init tty_init(void)
-{
- /*
- * dev_tty_driver and dev_console_driver are actually magic
- * devices which get redirected at open time. Nevertheless,
- * we register them so that register_chrdev is called
- * appropriately.
- */
- memset(&dev_tty_driver, 0, sizeof(struct tty_driver));
- dev_tty_driver.magic = TTY_DRIVER_MAGIC;
- dev_tty_driver.driver_name = "/dev/tty";
- dev_tty_driver.name = dev_tty_driver.driver_name + 5;
- dev_tty_driver.name_base = 0;
- dev_tty_driver.major = TTYAUX_MAJOR;
- dev_tty_driver.minor_start = 0;
- dev_tty_driver.num = 1;
- dev_tty_driver.type = TTY_DRIVER_TYPE_SYSTEM;
- dev_tty_driver.subtype = SYSTEM_TYPE_TTY;
-
- if (tty_register_driver(&dev_tty_driver))
- panic("Couldn't register /dev/tty driver\n");
-
- dev_syscons_driver = dev_tty_driver;
- dev_syscons_driver.driver_name = "/dev/console";
- dev_syscons_driver.name = dev_syscons_driver.driver_name + 5;
- dev_syscons_driver.major = TTYAUX_MAJOR;
- dev_syscons_driver.minor_start = 1;
- dev_syscons_driver.type = TTY_DRIVER_TYPE_SYSTEM;
- dev_syscons_driver.subtype = SYSTEM_TYPE_SYSCONS;
-
- if (tty_register_driver(&dev_syscons_driver))
- panic("Couldn't register /dev/console driver\n");
-
- /* console calls tty_register_driver() before kmalloc() works.
- * Thus, we can't devfs_register() then. Do so now, instead.
- */
-#ifdef CONFIG_VT
- con_init_devfs();
-#endif
-
-#ifdef CONFIG_UNIX98_PTYS
- dev_ptmx_driver = dev_tty_driver;
- dev_ptmx_driver.driver_name = "/dev/ptmx";
- dev_ptmx_driver.name = dev_ptmx_driver.driver_name + 5;
- dev_ptmx_driver.major= MAJOR(PTMX_DEV);
- dev_ptmx_driver.minor_start = MINOR(PTMX_DEV);
- dev_ptmx_driver.type = TTY_DRIVER_TYPE_SYSTEM;
- dev_ptmx_driver.subtype = SYSTEM_TYPE_SYSPTMX;
-
- if (tty_register_driver(&dev_ptmx_driver))
- panic("Couldn't register /dev/ptmx driver\n");
-#endif
-
-#ifdef CONFIG_VT
- dev_console_driver = dev_tty_driver;
- dev_console_driver.driver_name = "/dev/vc/0";
- dev_console_driver.name = dev_console_driver.driver_name + 5;
- dev_console_driver.major = TTY_MAJOR;
- dev_console_driver.type = TTY_DRIVER_TYPE_SYSTEM;
- dev_console_driver.subtype = SYSTEM_TYPE_CONSOLE;
-
- if (tty_register_driver(&dev_console_driver))
- panic("Couldn't register /dev/tty0 driver\n");
-
- kbd_init();
-#endif
-
-#ifdef CONFIG_ESPSERIAL /* init ESP before rs, so rs doesn't see the port */
- espserial_init();
-#endif
-#if defined(CONFIG_MVME162_SCC) || defined(CONFIG_BVME6000_SCC) || defined(CONFIG_MVME147_SCC)
- vme_scc_init();
-#endif
-#ifdef CONFIG_SERIAL_TX3912
- tx3912_rs_init();
-#endif
-#ifdef CONFIG_ROCKETPORT
- rp_init();
-#endif
-#ifdef CONFIG_SERIAL167
- serial167_init();
-#endif
-#ifdef CONFIG_CYCLADES
- cy_init();
-#endif
-#ifdef CONFIG_STALLION
- stl_init();
-#endif
-#ifdef CONFIG_ISTALLION
- stli_init();
-#endif
-#ifdef CONFIG_DIGI
- pcxe_init();
-#endif
-#ifdef CONFIG_DIGIEPCA
- pc_init();
-#endif
-#ifdef CONFIG_SPECIALIX
- specialix_init();
-#endif
-#if (defined(CONFIG_8xx) || defined(CONFIG_8260))
- rs_8xx_init();
-#endif /* CONFIG_8xx */
- pty_init();
-#ifdef CONFIG_MOXA_SMARTIO
- mxser_init();
-#endif
-#ifdef CONFIG_MOXA_INTELLIO
- moxa_init();
-#endif
-#ifdef CONFIG_VT
- vcs_init();
-#endif
-#ifdef CONFIG_TN3270
- tub3270_init();
-#endif
-#ifdef CONFIG_TN3215
- tty3215_init();
-#endif
-#ifdef CONFIG_HWC
- hwc_tty_init();
-#endif
-#ifdef CONFIG_A2232
- a2232board_init();
-#endif
-}
+++ /dev/null
-/*
- * linux/fs/exec.c
- *
- * Copyright (C) 1991, 1992 Linus Torvalds
- */
-
-/*
- * #!-checking implemented by tytso.
- */
-/*
- * Demand-loading implemented 01.12.91 - no need to read anything but
- * the header into memory. The inode of the executable is put into
- * "current->executable", and page faults do the actual loading. Clean.
- *
- * Once more I can proudly say that linux stood up to being changed: it
- * was less than 2 hours work to get demand-loading completely implemented.
- *
- * Demand loading changed July 1993 by Eric Youngdale. Use mmap instead,
- * current->executable is only used by the procfs. This allows a dispatch
- * table to check for several different types of binary formats. We keep
- * trying until we recognize the file or we run out of supported binary
- * formats.
- */
-
-#include <linux/config.h>
-#include <linux/slab.h>
-#include <linux/file.h>
-#include <linux/mman.h>
-#include <linux/a.out.h>
-#include <linux/stat.h>
-#include <linux/fcntl.h>
-#include <linux/smp_lock.h>
-#include <linux/init.h>
-#include <linux/pagemap.h>
-#include <linux/highmem.h>
-#include <linux/spinlock.h>
-#include <linux/personality.h>
-#include <linux/swap.h>
-#include <linux/utsname.h>
-#define __NO_VERSION__
-#include <linux/module.h>
-
-#include <asm/uaccess.h>
-#include <asm/pgalloc.h>
-#include <asm/mmu_context.h>
-
-#ifdef CONFIG_KMOD
-#include <linux/kmod.h>
-#endif
-
-int core_uses_pid;
-char core_pattern[65] = "core";
-/* The maximal length of core_pattern is also specified in sysctl.c */
-
-static struct linux_binfmt *formats;
-static rwlock_t binfmt_lock = RW_LOCK_UNLOCKED;
-
-int register_binfmt(struct linux_binfmt * fmt)
-{
- struct linux_binfmt ** tmp = &formats;
-
- if (!fmt)
- return -EINVAL;
- if (fmt->next)
- return -EBUSY;
- write_lock(&binfmt_lock);
- while (*tmp) {
- if (fmt == *tmp) {
- write_unlock(&binfmt_lock);
- return -EBUSY;
- }
- tmp = &(*tmp)->next;
- }
- fmt->next = formats;
- formats = fmt;
- write_unlock(&binfmt_lock);
- return 0;
-}
-
-int unregister_binfmt(struct linux_binfmt * fmt)
-{
- struct linux_binfmt ** tmp = &formats;
-
- write_lock(&binfmt_lock);
- while (*tmp) {
- if (fmt == *tmp) {
- *tmp = fmt->next;
- write_unlock(&binfmt_lock);
- return 0;
- }
- tmp = &(*tmp)->next;
- }
- write_unlock(&binfmt_lock);
- return -EINVAL;
-}
-
-static inline void put_binfmt(struct linux_binfmt * fmt)
-{
- if (fmt->module)
- __MOD_DEC_USE_COUNT(fmt->module);
-}
-
-/*
- * Note that a shared library must be both readable and executable due to
- * security reasons.
- *
- * Also note that we take the address to load from from the file itself.
- */
-asmlinkage long sys_uselib(const char * library)
-{
- struct file * file;
- struct nameidata nd;
- int error;
-
- error = user_path_walk(library, &nd);
- if (error)
- goto out;
-
- error = -EINVAL;
- if (!S_ISREG(nd.dentry->d_inode->i_mode))
- goto exit;
-
- error = permission(nd.dentry->d_inode, MAY_READ | MAY_EXEC);
- if (error)
- goto exit;
-
- file = dentry_open(nd.dentry, nd.mnt, O_RDONLY);
- error = PTR_ERR(file);
- if (IS_ERR(file))
- goto out;
-
- error = -ENOEXEC;
- if(file->f_op && file->f_op->read) {
- struct linux_binfmt * fmt;
-
- read_lock(&binfmt_lock);
- for (fmt = formats ; fmt ; fmt = fmt->next) {
- if (!fmt->load_shlib)
- continue;
- if (!try_inc_mod_count(fmt->module))
- continue;
- read_unlock(&binfmt_lock);
- error = fmt->load_shlib(file);
- read_lock(&binfmt_lock);
- put_binfmt(fmt);
- if (error != -ENOEXEC)
- break;
- }
- read_unlock(&binfmt_lock);
- }
- fput(file);
-out:
- return error;
-exit:
- path_release(&nd);
- goto out;
-}
-
-/*
- * count() counts the number of arguments/envelopes
- */
-static int count(char ** argv, int max)
-{
- int i = 0;
-
- if (argv != NULL) {
- for (;;) {
- char * p;
-
- if (get_user(p, argv))
- return -EFAULT;
- if (!p)
- break;
- argv++;
- if(++i > max)
- return -E2BIG;
- }
- }
- return i;
-}
-
-/*
- * 'copy_strings()' copies argument/envelope strings from user
- * memory to free pages in kernel mem. These are in a format ready
- * to be put directly into the top of new user memory.
- */
-int copy_strings(int argc,char ** argv, struct linux_binprm *bprm)
-{
- struct page *kmapped_page = NULL;
- char *kaddr = NULL;
- int ret;
-
- while (argc-- > 0) {
- char *str;
- int len;
- unsigned long pos;
-
- if (get_user(str, argv+argc) ||
- !(len = strnlen_user(str, bprm->p))) {
- ret = -EFAULT;
- goto out;
- }
-
- if (bprm->p < len) {
- ret = -E2BIG;
- goto out;
- }
-
- bprm->p -= len;
- /* XXX: add architecture specific overflow check here. */
- pos = bprm->p;
-
- while (len > 0) {
- int i, new, err;
- int offset, bytes_to_copy;
- struct page *page;
-
- offset = pos % PAGE_SIZE;
- i = pos/PAGE_SIZE;
- page = bprm->page[i];
- new = 0;
- if (!page) {
- page = alloc_page(GFP_HIGHUSER);
- bprm->page[i] = page;
- if (!page) {
- ret = -ENOMEM;
- goto out;
- }
- new = 1;
- }
-
- if (page != kmapped_page) {
- if (kmapped_page)
- kunmap(kmapped_page);
- kmapped_page = page;
- kaddr = kmap(kmapped_page);
- }
- if (new && offset)
- memset(kaddr, 0, offset);
- bytes_to_copy = PAGE_SIZE - offset;
- if (bytes_to_copy > len) {
- bytes_to_copy = len;
- if (new)
- memset(kaddr+offset+len, 0,
- PAGE_SIZE-offset-len);
- }
- err = copy_from_user(kaddr+offset, str, bytes_to_copy);
- if (err) {
- ret = -EFAULT;
- goto out;
- }
-
- pos += bytes_to_copy;
- str += bytes_to_copy;
- len -= bytes_to_copy;
- }
- }
- ret = 0;
-out:
- if (kmapped_page)
- kunmap(kmapped_page);
- return ret;
-}
-
-/*
- * Like copy_strings, but get argv and its values from kernel memory.
- */
-int copy_strings_kernel(int argc,char ** argv, struct linux_binprm *bprm)
-{
- int r;
- mm_segment_t oldfs = get_fs();
- set_fs(KERNEL_DS);
- r = copy_strings(argc, argv, bprm);
- set_fs(oldfs);
- return r;
-}
-
-/*
- * This routine is used to map in a page into an address space: needed by
- * execve() for the initial stack and environment pages.
- *
- * tsk->mmap_sem is held for writing.
- */
-void put_dirty_page(struct task_struct * tsk, struct page *page, unsigned long address)
-{
- pgd_t * pgd;
- pmd_t * pmd;
- pte_t * pte;
-
- if (page_count(page) != 1)
- printk(KERN_ERR "mem_map disagrees with %p at %08lx\n", page, address);
- pgd = pgd_offset(tsk->mm, address);
-
- spin_lock(&tsk->mm->page_table_lock);
- pmd = pmd_alloc(tsk->mm, pgd, address);
- if (!pmd)
- goto out;
- pte = pte_alloc(tsk->mm, pmd, address);
- if (!pte)
- goto out;
- if (!pte_none(*pte))
- goto out;
- lru_cache_add(page);
- flush_dcache_page(page);
- flush_page_to_ram(page);
- set_pte(pte, pte_mkdirty(pte_mkwrite(mk_pte(page, PAGE_COPY))));
- XENO_flush_page_update_queue();
- tsk->mm->rss++;
- spin_unlock(&tsk->mm->page_table_lock);
-
- /* no need for flush_tlb */
- return;
-out:
- spin_unlock(&tsk->mm->page_table_lock);
- __free_page(page);
- force_sig(SIGKILL, tsk);
- return;
-}
-
-int setup_arg_pages(struct linux_binprm *bprm)
-{
- unsigned long stack_base;
- struct vm_area_struct *mpnt;
- int i;
-
- stack_base = STACK_TOP - MAX_ARG_PAGES*PAGE_SIZE;
-
- bprm->p += stack_base;
- if (bprm->loader)
- bprm->loader += stack_base;
- bprm->exec += stack_base;
-
- mpnt = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL);
- if (!mpnt)
- return -ENOMEM;
-
- down_write(¤t->mm->mmap_sem);
- {
- mpnt->vm_mm = current->mm;
- mpnt->vm_start = PAGE_MASK & (unsigned long) bprm->p;
- mpnt->vm_end = STACK_TOP;
- mpnt->vm_page_prot = PAGE_COPY;
- mpnt->vm_flags = VM_STACK_FLAGS;
- mpnt->vm_ops = NULL;
- mpnt->vm_pgoff = 0;
- mpnt->vm_file = NULL;
- mpnt->vm_private_data = (void *) 0;
- insert_vm_struct(current->mm, mpnt);
- current->mm->total_vm = (mpnt->vm_end - mpnt->vm_start) >> PAGE_SHIFT;
- }
-
- for (i = 0 ; i < MAX_ARG_PAGES ; i++) {
- struct page *page = bprm->page[i];
- if (page) {
- bprm->page[i] = NULL;
- put_dirty_page(current,page,stack_base);
- }
- stack_base += PAGE_SIZE;
- }
- up_write(¤t->mm->mmap_sem);
-
- return 0;
-}
-
-struct file *open_exec(const char *name)
-{
- struct nameidata nd;
- struct inode *inode;
- struct file *file;
- int err = 0;
-
- err = path_lookup(name, LOOKUP_FOLLOW|LOOKUP_POSITIVE, &nd);
- file = ERR_PTR(err);
- if (!err) {
- inode = nd.dentry->d_inode;
- file = ERR_PTR(-EACCES);
- if (!(nd.mnt->mnt_flags & MNT_NOEXEC) &&
- S_ISREG(inode->i_mode)) {
- int err = permission(inode, MAY_EXEC);
- if (!err && !(inode->i_mode & 0111))
- err = -EACCES;
- file = ERR_PTR(err);
- if (!err) {
- file = dentry_open(nd.dentry, nd.mnt, O_RDONLY);
- if (!IS_ERR(file)) {
- err = deny_write_access(file);
- if (err) {
- fput(file);
- file = ERR_PTR(err);
- }
- }
-out:
- return file;
- }
- }
- path_release(&nd);
- }
- goto out;
-}
-
-int kernel_read(struct file *file, unsigned long offset,
- char * addr, unsigned long count)
-{
- mm_segment_t old_fs;
- loff_t pos = offset;
- int result = -ENOSYS;
-
- if (!file->f_op->read)
- goto fail;
- old_fs = get_fs();
- set_fs(get_ds());
- result = file->f_op->read(file, addr, count, &pos);
- set_fs(old_fs);
-fail:
- return result;
-}
-
-static int exec_mmap(void)
-{
- struct mm_struct * mm, * old_mm;
-
- old_mm = current->mm;
- if (old_mm && atomic_read(&old_mm->mm_users) == 1) {
- mm_release();
- exit_mmap(old_mm);
- return 0;
- }
-
- mm = mm_alloc();
- if (mm) {
- struct mm_struct *active_mm;
-
- if (init_new_context(current, mm)) {
- mmdrop(mm);
- return -ENOMEM;
- }
-
- /* Add it to the list of mm's */
- spin_lock(&mmlist_lock);
- list_add(&mm->mmlist, &init_mm.mmlist);
- mmlist_nr++;
- spin_unlock(&mmlist_lock);
-
- task_lock(current);
- active_mm = current->active_mm;
- current->mm = mm;
- current->active_mm = mm;
- task_unlock(current);
- activate_mm(active_mm, mm);
- mm_release();
- if (old_mm) {
- if (active_mm != old_mm) BUG();
- mmput(old_mm);
- return 0;
- }
- mmdrop(active_mm);
- return 0;
- }
- return -ENOMEM;
-}
-
-/*
- * This function makes sure the current process has its own signal table,
- * so that flush_signal_handlers can later reset the handlers without
- * disturbing other processes. (Other processes might share the signal
- * table via the CLONE_SIGNAL option to clone().)
- */
-
-static inline int make_private_signals(void)
-{
- struct signal_struct * newsig;
-
- if (atomic_read(¤t->sig->count) <= 1)
- return 0;
- newsig = kmem_cache_alloc(sigact_cachep, GFP_KERNEL);
- if (newsig == NULL)
- return -ENOMEM;
- spin_lock_init(&newsig->siglock);
- atomic_set(&newsig->count, 1);
- memcpy(newsig->action, current->sig->action, sizeof(newsig->action));
- spin_lock_irq(¤t->sigmask_lock);
- current->sig = newsig;
- spin_unlock_irq(¤t->sigmask_lock);
- return 0;
-}
-
-/*
- * If make_private_signals() made a copy of the signal table, decrement the
- * refcount of the original table, and free it if necessary.
- * We don't do that in make_private_signals() so that we can back off
- * in flush_old_exec() if an error occurs after calling make_private_signals().
- */
-
-static inline void release_old_signals(struct signal_struct * oldsig)
-{
- if (current->sig == oldsig)
- return;
- if (atomic_dec_and_test(&oldsig->count))
- kmem_cache_free(sigact_cachep, oldsig);
-}
-
-/*
- * These functions flushes out all traces of the currently running executable
- * so that a new one can be started
- */
-
-static inline void flush_old_files(struct files_struct * files)
-{
- long j = -1;
-
- write_lock(&files->file_lock);
- for (;;) {
- unsigned long set, i;
-
- j++;
- i = j * __NFDBITS;
- if (i >= files->max_fds || i >= files->max_fdset)
- break;
- set = files->close_on_exec->fds_bits[j];
- if (!set)
- continue;
- files->close_on_exec->fds_bits[j] = 0;
- write_unlock(&files->file_lock);
- for ( ; set ; i++,set >>= 1) {
- if (set & 1) {
- sys_close(i);
- }
- }
- write_lock(&files->file_lock);
-
- }
- write_unlock(&files->file_lock);
-}
-
-/*
- * An execve() will automatically "de-thread" the process.
- * Note: we don't have to hold the tasklist_lock to test
- * whether we migth need to do this. If we're not part of
- * a thread group, there is no way we can become one
- * dynamically. And if we are, we only need to protect the
- * unlink - even if we race with the last other thread exit,
- * at worst the list_del_init() might end up being a no-op.
- */
-static inline void de_thread(struct task_struct *tsk)
-{
- if (!list_empty(&tsk->thread_group)) {
- write_lock_irq(&tasklist_lock);
- list_del_init(&tsk->thread_group);
- write_unlock_irq(&tasklist_lock);
- }
-
- /* Minor oddity: this might stay the same. */
- tsk->tgid = tsk->pid;
-}
-
-int flush_old_exec(struct linux_binprm * bprm)
-{
- char * name;
- int i, ch, retval;
- struct signal_struct * oldsig;
-
- /*
- * Make sure we have a private signal table
- */
- oldsig = current->sig;
- retval = make_private_signals();
- if (retval) goto flush_failed;
-
- /*
- * Release all of the old mmap stuff
- */
- retval = exec_mmap();
- if (retval) goto mmap_failed;
-
- /* This is the point of no return */
- release_old_signals(oldsig);
-
- current->sas_ss_sp = current->sas_ss_size = 0;
-
- if (current->euid == current->uid && current->egid == current->gid)
- current->mm->dumpable = 1;
- name = bprm->filename;
- for (i=0; (ch = *(name++)) != '\0';) {
- if (ch == '/')
- i = 0;
- else
- if (i < 15)
- current->comm[i++] = ch;
- }
- current->comm[i] = '\0';
-
- flush_thread();
-
- de_thread(current);
-
- if (bprm->e_uid != current->euid || bprm->e_gid != current->egid ||
- permission(bprm->file->f_dentry->d_inode,MAY_READ))
- current->mm->dumpable = 0;
-
- /* An exec changes our domain. We are no longer part of the thread
- group */
-
- current->self_exec_id++;
-
- flush_signal_handlers(current);
- flush_old_files(current->files);
-
- return 0;
-
-mmap_failed:
-flush_failed:
- spin_lock_irq(¤t->sigmask_lock);
- if (current->sig != oldsig) {
- kmem_cache_free(sigact_cachep, current->sig);
- current->sig = oldsig;
- }
- spin_unlock_irq(¤t->sigmask_lock);
- return retval;
-}
-
-/*
- * We mustn't allow tracing of suid binaries, unless
- * the tracer has the capability to trace anything..
- */
-static inline int must_not_trace_exec(struct task_struct * p)
-{
- return (p->ptrace & PT_PTRACED) && !(p->ptrace & PT_PTRACE_CAP);
-}
-
-/*
- * Fill the binprm structure from the inode.
- * Check permissions, then read the first 128 (BINPRM_BUF_SIZE) bytes
- */
-int prepare_binprm(struct linux_binprm *bprm)
-{
- int mode;
- struct inode * inode = bprm->file->f_dentry->d_inode;
-
- mode = inode->i_mode;
- /*
- * Check execute perms again - if the caller has CAP_DAC_OVERRIDE,
- * vfs_permission lets a non-executable through
- */
- if (!(mode & 0111)) /* with at least _one_ execute bit set */
- return -EACCES;
- if (bprm->file->f_op == NULL)
- return -EACCES;
-
- bprm->e_uid = current->euid;
- bprm->e_gid = current->egid;
-
- if(!(bprm->file->f_vfsmnt->mnt_flags & MNT_NOSUID)) {
- /* Set-uid? */
- if (mode & S_ISUID)
- bprm->e_uid = inode->i_uid;
-
- /* Set-gid? */
- /*
- * If setgid is set but no group execute bit then this
- * is a candidate for mandatory locking, not a setgid
- * executable.
- */
- if ((mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP))
- bprm->e_gid = inode->i_gid;
- }
-
- /* We don't have VFS support for capabilities yet */
- cap_clear(bprm->cap_inheritable);
- cap_clear(bprm->cap_permitted);
- cap_clear(bprm->cap_effective);
-
- /* To support inheritance of root-permissions and suid-root
- * executables under compatibility mode, we raise all three
- * capability sets for the file.
- *
- * If only the real uid is 0, we only raise the inheritable
- * and permitted sets of the executable file.
- */
-
- if (!issecure(SECURE_NOROOT)) {
- if (bprm->e_uid == 0 || current->uid == 0) {
- cap_set_full(bprm->cap_inheritable);
- cap_set_full(bprm->cap_permitted);
- }
- if (bprm->e_uid == 0)
- cap_set_full(bprm->cap_effective);
- }
-
- memset(bprm->buf,0,BINPRM_BUF_SIZE);
- return kernel_read(bprm->file,0,bprm->buf,BINPRM_BUF_SIZE);
-}
-
-/*
- * This function is used to produce the new IDs and capabilities
- * from the old ones and the file's capabilities.
- *
- * The formula used for evolving capabilities is:
- *
- * pI' = pI
- * (***) pP' = (fP & X) | (fI & pI)
- * pE' = pP' & fE [NB. fE is 0 or ~0]
- *
- * I=Inheritable, P=Permitted, E=Effective // p=process, f=file
- * ' indicates post-exec(), and X is the global 'cap_bset'.
- *
- */
-
-void compute_creds(struct linux_binprm *bprm)
-{
- kernel_cap_t new_permitted, working;
- int do_unlock = 0;
-
- new_permitted = cap_intersect(bprm->cap_permitted, cap_bset);
- working = cap_intersect(bprm->cap_inheritable,
- current->cap_inheritable);
- new_permitted = cap_combine(new_permitted, working);
-
- if (bprm->e_uid != current->uid || bprm->e_gid != current->gid ||
- !cap_issubset(new_permitted, current->cap_permitted)) {
- current->mm->dumpable = 0;
-
- lock_kernel();
- if (must_not_trace_exec(current)
- || atomic_read(¤t->fs->count) > 1
- || atomic_read(¤t->files->count) > 1
- || atomic_read(¤t->sig->count) > 1) {
- if(!capable(CAP_SETUID)) {
- bprm->e_uid = current->uid;
- bprm->e_gid = current->gid;
- }
- if(!capable(CAP_SETPCAP)) {
- new_permitted = cap_intersect(new_permitted,
- current->cap_permitted);
- }
- }
- do_unlock = 1;
- }
-
-
- /* For init, we want to retain the capabilities set
- * in the init_task struct. Thus we skip the usual
- * capability rules */
- if (current->pid != 1) {
- current->cap_permitted = new_permitted;
- current->cap_effective =
- cap_intersect(new_permitted, bprm->cap_effective);
- }
-
- /* AUD: Audit candidate if current->cap_effective is set */
-
- current->suid = current->euid = current->fsuid = bprm->e_uid;
- current->sgid = current->egid = current->fsgid = bprm->e_gid;
-
- if(do_unlock)
- unlock_kernel();
- current->keep_capabilities = 0;
-}
-
-
-void remove_arg_zero(struct linux_binprm *bprm)
-{
- if (bprm->argc) {
- unsigned long offset;
- char * kaddr;
- struct page *page;
-
- offset = bprm->p % PAGE_SIZE;
- goto inside;
-
- while (bprm->p++, *(kaddr+offset++)) {
- if (offset != PAGE_SIZE)
- continue;
- offset = 0;
- kunmap(page);
-inside:
- page = bprm->page[bprm->p/PAGE_SIZE];
- kaddr = kmap(page);
- }
- kunmap(page);
- bprm->argc--;
- }
-}
-
-/*
- * cycle the list of binary formats handler, until one recognizes the image
- */
-int search_binary_handler(struct linux_binprm *bprm,struct pt_regs *regs)
-{
- int try,retval=0;
- struct linux_binfmt *fmt;
-#ifdef __alpha__
- /* handle /sbin/loader.. */
- {
- struct exec * eh = (struct exec *) bprm->buf;
-
- if (!bprm->loader && eh->fh.f_magic == 0x183 &&
- (eh->fh.f_flags & 0x3000) == 0x3000)
- {
- struct file * file;
- unsigned long loader;
-
- allow_write_access(bprm->file);
- fput(bprm->file);
- bprm->file = NULL;
-
- loader = PAGE_SIZE*MAX_ARG_PAGES-sizeof(void *);
-
- file = open_exec("/sbin/loader");
- retval = PTR_ERR(file);
- if (IS_ERR(file))
- return retval;
-
- /* Remember if the application is TASO. */
- bprm->sh_bang = eh->ah.entry < 0x100000000;
-
- bprm->file = file;
- bprm->loader = loader;
- retval = prepare_binprm(bprm);
- if (retval<0)
- return retval;
- /* should call search_binary_handler recursively here,
- but it does not matter */
- }
- }
-#endif
- /* kernel module loader fixup */
- /* so we don't try to load run modprobe in kernel space. */
- set_fs(USER_DS);
- for (try=0; try<2; try++) {
- read_lock(&binfmt_lock);
- for (fmt = formats ; fmt ; fmt = fmt->next) {
- int (*fn)(struct linux_binprm *, struct pt_regs *) = fmt->load_binary;
- if (!fn)
- continue;
- if (!try_inc_mod_count(fmt->module))
- continue;
- read_unlock(&binfmt_lock);
- retval = fn(bprm, regs);
- if (retval >= 0) {
- put_binfmt(fmt);
- allow_write_access(bprm->file);
- if (bprm->file)
- fput(bprm->file);
- bprm->file = NULL;
- current->did_exec = 1;
- return retval;
- }
- read_lock(&binfmt_lock);
- put_binfmt(fmt);
- if (retval != -ENOEXEC)
- break;
- if (!bprm->file) {
- read_unlock(&binfmt_lock);
- return retval;
- }
- }
- read_unlock(&binfmt_lock);
- if (retval != -ENOEXEC) {
- break;
-#ifdef CONFIG_KMOD
- }else{
-#define printable(c) (((c)=='\t') || ((c)=='\n') || (0x20<=(c) && (c)<=0x7e))
- char modname[20];
- if (printable(bprm->buf[0]) &&
- printable(bprm->buf[1]) &&
- printable(bprm->buf[2]) &&
- printable(bprm->buf[3]))
- break; /* -ENOEXEC */
- sprintf(modname, "binfmt-%04x", *(unsigned short *)(&bprm->buf[2]));
- request_module(modname);
-#endif
- }
- }
- return retval;
-}
-
-
-/*
- * sys_execve() executes a new program.
- */
-int do_execve(char * filename, char ** argv, char ** envp, struct pt_regs * regs)
-{
- struct linux_binprm bprm;
- struct file *file;
- int retval;
- int i;
-
- file = open_exec(filename);
-
- retval = PTR_ERR(file);
- if (IS_ERR(file))
- return retval;
-
- bprm.p = PAGE_SIZE*MAX_ARG_PAGES-sizeof(void *);
- memset(bprm.page, 0, MAX_ARG_PAGES*sizeof(bprm.page[0]));
-
- bprm.file = file;
- bprm.filename = filename;
- bprm.sh_bang = 0;
- bprm.loader = 0;
- bprm.exec = 0;
- if ((bprm.argc = count(argv, bprm.p / sizeof(void *))) < 0) {
- allow_write_access(file);
- fput(file);
- return bprm.argc;
- }
-
- if ((bprm.envc = count(envp, bprm.p / sizeof(void *))) < 0) {
- allow_write_access(file);
- fput(file);
- return bprm.envc;
- }
-
- retval = prepare_binprm(&bprm);
- if (retval < 0)
- goto out;
-
- retval = copy_strings_kernel(1, &bprm.filename, &bprm);
- if (retval < 0)
- goto out;
-
- bprm.exec = bprm.p;
- retval = copy_strings(bprm.envc, envp, &bprm);
- if (retval < 0)
- goto out;
-
- retval = copy_strings(bprm.argc, argv, &bprm);
- if (retval < 0)
- goto out;
-
- retval = search_binary_handler(&bprm,regs);
- if (retval >= 0)
- /* execve success */
- return retval;
-
-out:
- /* Something went wrong, return the inode and free the argument pages*/
- allow_write_access(bprm.file);
- if (bprm.file)
- fput(bprm.file);
-
- for (i = 0 ; i < MAX_ARG_PAGES ; i++) {
- struct page * page = bprm.page[i];
- if (page)
- __free_page(page);
- }
-
- return retval;
-}
-
-void set_binfmt(struct linux_binfmt *new)
-{
- struct linux_binfmt *old = current->binfmt;
- if (new && new->module)
- __MOD_INC_USE_COUNT(new->module);
- current->binfmt = new;
- if (old && old->module)
- __MOD_DEC_USE_COUNT(old->module);
-}
-
-#define CORENAME_MAX_SIZE 64
-
-/* format_corename will inspect the pattern parameter, and output a
- * name into corename, which must have space for at least
- * CORENAME_MAX_SIZE bytes plus one byte for the zero terminator.
- */
-void format_corename(char *corename, const char *pattern, long signr)
-{
- const char *pat_ptr = pattern;
- char *out_ptr = corename;
- char *const out_end = corename + CORENAME_MAX_SIZE;
- int rc;
- int pid_in_pattern = 0;
-
- /* Repeat as long as we have more pattern to process and more output
- space */
- while (*pat_ptr) {
- if (*pat_ptr != '%') {
- if (out_ptr == out_end)
- goto out;
- *out_ptr++ = *pat_ptr++;
- } else {
- switch (*++pat_ptr) {
- case 0:
- goto out;
- /* Double percent, output one percent */
- case '%':
- if (out_ptr == out_end)
- goto out;
- *out_ptr++ = '%';
- break;
- /* pid */
- case 'p':
- pid_in_pattern = 1;
- rc = snprintf(out_ptr, out_end - out_ptr,
- "%d", current->pid);
- if (rc > out_end - out_ptr)
- goto out;
- out_ptr += rc;
- break;
- /* uid */
- case 'u':
- rc = snprintf(out_ptr, out_end - out_ptr,
- "%d", current->uid);
- if (rc > out_end - out_ptr)
- goto out;
- out_ptr += rc;
- break;
- /* gid */
- case 'g':
- rc = snprintf(out_ptr, out_end - out_ptr,
- "%d", current->gid);
- if (rc > out_end - out_ptr)
- goto out;
- out_ptr += rc;
- break;
- /* signal that caused the coredump */
- case 's':
- rc = snprintf(out_ptr, out_end - out_ptr,
- "%ld", signr);
- if (rc > out_end - out_ptr)
- goto out;
- out_ptr += rc;
- break;
- /* UNIX time of coredump */
- case 't': {
- struct timeval tv;
- do_gettimeofday(&tv);
- rc = snprintf(out_ptr, out_end - out_ptr,
- "%ld", tv.tv_sec);
- if (rc > out_end - out_ptr)
- goto out;
- out_ptr += rc;
- break;
- }
- /* hostname */
- case 'h':
- down_read(&uts_sem);
- rc = snprintf(out_ptr, out_end - out_ptr,
- "%s", system_utsname.nodename);
- up_read(&uts_sem);
- if (rc > out_end - out_ptr)
- goto out;
- out_ptr += rc;
- break;
- /* executable */
- case 'e':
- rc = snprintf(out_ptr, out_end - out_ptr,
- "%s", current->comm);
- if (rc > out_end - out_ptr)
- goto out;
- out_ptr += rc;
- break;
- default:
- break;
- }
- ++pat_ptr;
- }
- }
- /* Backward compatibility with core_uses_pid:
- *
- * If core_pattern does not include a %p (as is the default)
- * and core_uses_pid is set, then .%pid will be appended to
- * the filename */
- if (!pid_in_pattern
- && (core_uses_pid || atomic_read(¤t->mm->mm_users) != 1)) {
- rc = snprintf(out_ptr, out_end - out_ptr,
- ".%d", current->pid);
- if (rc > out_end - out_ptr)
- goto out;
- out_ptr += rc;
- }
- out:
- *out_ptr = 0;
-}
-
-int do_coredump(long signr, struct pt_regs * regs)
-{
- struct linux_binfmt * binfmt;
- char corename[CORENAME_MAX_SIZE + 1];
- struct file * file;
- struct inode * inode;
- int retval = 0;
-
- lock_kernel();
- binfmt = current->binfmt;
- if (!binfmt || !binfmt->core_dump)
- goto fail;
- if (!current->mm->dumpable)
- goto fail;
- current->mm->dumpable = 0;
- if (current->rlim[RLIMIT_CORE].rlim_cur < binfmt->min_coredump)
- goto fail;
-
- format_corename(corename, core_pattern, signr);
- file = filp_open(corename, O_CREAT | 2 | O_NOFOLLOW, 0600);
- if (IS_ERR(file))
- goto fail;
- inode = file->f_dentry->d_inode;
- if (inode->i_nlink > 1)
- goto close_fail; /* multiple links - don't dump */
- if (d_unhashed(file->f_dentry))
- goto close_fail;
-
- if (!S_ISREG(inode->i_mode))
- goto close_fail;
- if (!file->f_op)
- goto close_fail;
- if (!file->f_op->write)
- goto close_fail;
- if (do_truncate(file->f_dentry, 0) != 0)
- goto close_fail;
-
- retval = binfmt->core_dump(signr, regs, file);
-
-close_fail:
- filp_close(file, NULL);
-fail:
- unlock_kernel();
- return retval;
-}
+++ /dev/null
-/*
- * include/asm-i386/bugs.h
- *
- * Copyright (C) 1994 Linus Torvalds
- *
- * Cyrix stuff, June 1998 by:
- * - Rafael R. Reilova (moved everything from head.S),
- * <rreilova@ececs.uc.edu>
- * - Channing Corn (tests & fixes),
- * - Andrew D. Balsa (code cleanup).
- *
- * Pentium III FXSR, SSE support
- * Gareth Hughes <gareth@valinux.com>, May 2000
- */
-
-/*
- * This is included by init/main.c to check for architecture-dependent bugs.
- *
- * Needs:
- * void check_bugs(void);
- */
-
-#include <linux/config.h>
-#include <asm/processor.h>
-#include <asm/i387.h>
-#include <asm/msr.h>
-
-
-static void __init check_fpu(void)
-{
- boot_cpu_data.fdiv_bug = 0;
-}
-
-static void __init check_hlt(void)
-{
- boot_cpu_data.hlt_works_ok = 1;
-}
-
-static void __init check_bugs(void)
-{
- extern void __init boot_init_fpu(void);
-
- identify_cpu(&boot_cpu_data);
- boot_init_fpu();
-#ifndef CONFIG_SMP
- printk("CPU: ");
- print_cpu_info(&boot_cpu_data);
-#endif
- check_fpu();
- check_hlt();
- system_utsname.machine[1] = '0' +
- (boot_cpu_data.x86 > 6 ? 6 : boot_cpu_data.x86);
-}
+++ /dev/null
-#ifndef __ARCH_DESC_H
-#define __ARCH_DESC_H
-
-#include <asm/ldt.h>
-
-#ifndef __ASSEMBLY__
-
-struct desc_struct {
- unsigned long a,b;
-};
-
-struct Xgt_desc_struct {
- unsigned short size;
- unsigned long address __attribute__((packed));
-};
-
-extern struct desc_struct default_ldt[];
-
-static inline void clear_LDT(void)
-{
- queue_set_ldt((unsigned long)&default_ldt[0], 5);
-}
-
-static inline void load_LDT(struct mm_struct *mm)
-{
- void *segments = mm->context.segments;
- int count = LDT_ENTRIES;
-
- if (!segments) {
- segments = &default_ldt[0];
- count = 5;
- }
-
- queue_set_ldt((unsigned long)segments, count);
-}
-
-#endif /* __ASSEMBLY__ */
-
-#endif /* __ARCH_DESC_H__ */
+++ /dev/null
-/*
- * fixmap.h: compile-time virtual memory allocation
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Copyright (C) 1998 Ingo Molnar
- *
- * Support of BIGMEM added by Gerhard Wichert, Siemens AG, July 1999
- */
-
-#ifndef _ASM_FIXMAP_H
-#define _ASM_FIXMAP_H
-
-#include <linux/config.h>
-#include <linux/kernel.h>
-#include <asm/apicdef.h>
-#include <asm/page.h>
-
-/*
- * Here we define all the compile-time 'special' virtual
- * addresses. The point is to have a constant address at
- * compile time, but to set the physical address only
- * in the boot process. We allocate these special addresses
- * from the end of virtual memory (0xfffff000) backwards.
- * Also this lets us do fail-safe vmalloc(), we
- * can guarantee that these special addresses and
- * vmalloc()-ed addresses never overlap.
- *
- * these 'compile-time allocated' memory buffers are
- * fixed-size 4k pages. (or larger if used with an increment
- * highger than 1) use fixmap_set(idx,phys) to associate
- * physical memory with fixmap indices.
- *
- * TLB entries of such buffers will not be flushed across
- * task switches.
- */
-
-enum fixed_addresses {
-#ifdef CONFIG_HIGHMEM_XXX
- FIX_KMAP_BEGIN, /* reserved pte's for temporary kernel mappings */
- FIX_KMAP_END = FIX_KMAP_BEGIN+(KM_TYPE_NR*NR_CPUS)-1,
-#endif
- FIX_BLKRING_BASE,
- FIX_NETRING0_BASE,
- FIX_NETRING1_BASE,
- FIX_NETRING2_BASE,
- FIX_NETRING3_BASE,
- __end_of_permanent_fixed_addresses,
- __end_of_fixed_addresses
-};
-
-extern void __set_fixmap (enum fixed_addresses idx,
- unsigned long phys, pgprot_t flags);
-
-#define set_fixmap(idx, phys) \
- __set_fixmap(idx, phys, PAGE_KERNEL)
-/*
- * Some hardware wants to get fixmapped without caching.
- */
-#define set_fixmap_nocache(idx, phys) \
- __set_fixmap(idx, phys, PAGE_KERNEL_NOCACHE)
-/*
- * used by vmalloc.c.
- *
- * Leave one empty page between vmalloc'ed areas and
- * the start of the fixmap, and leave one page empty
- * at the top of mem..
- */
-#define FIXADDR_TOP (HYPERVISOR_VIRT_START - 2*PAGE_SIZE)
-#define __FIXADDR_SIZE (__end_of_fixed_addresses << PAGE_SHIFT)
-#define FIXADDR_START (FIXADDR_TOP - __FIXADDR_SIZE)
-
-#define __fix_to_virt(x) (FIXADDR_TOP - ((x) << PAGE_SHIFT))
-
-/*
- * 'index to address' translation. If anyone tries to use the idx
- * directly without tranlation, we catch the bug with a NULL-deference
- * kernel oops. Illegal ranges of incoming indices are caught too.
- */
-static inline unsigned long fix_to_virt(unsigned int idx)
-{
- return __fix_to_virt(idx);
-}
-
-#endif
+++ /dev/null
-#error "Highmem unsupported!"
-
+++ /dev/null
-#ifndef _ASM_HW_IRQ_H
-#define _ASM_HW_IRQ_H
-
-/*
- * linux/include/asm/hw_irq.h
- *
- * (C) 1992, 1993 Linus Torvalds, (C) 1997 Ingo Molnar
- */
-
-#include <linux/config.h>
-#include <linux/smp.h>
-#include <asm/atomic.h>
-#include <asm/irq.h>
-
-#define SYSCALL_VECTOR 0x80
-
-extern int irq_vector[NR_IRQS];
-
-extern atomic_t irq_err_count;
-extern atomic_t irq_mis_count;
-
-extern char _stext, _etext;
-
-extern unsigned long prof_cpu_mask;
-extern unsigned int * prof_buffer;
-extern unsigned long prof_len;
-extern unsigned long prof_shift;
-
-/*
- * x86 profiling function, SMP safe. We might want to do this in
- * assembly totally?
- */
-static inline void x86_do_profile (unsigned long eip)
-{
- if (!prof_buffer)
- return;
-
- /*
- * Only measure the CPUs specified by /proc/irq/prof_cpu_mask.
- * (default is all CPUs.)
- */
- if (!((1<<smp_processor_id()) & prof_cpu_mask))
- return;
-
- eip -= (unsigned long) &_stext;
- eip >>= prof_shift;
- /*
- * Don't ignore out-of-bounds EIP values silently,
- * put them into the last histogram slot, so if
- * present, they will show up as a sharp peak.
- */
- if (eip > prof_len-1)
- eip = prof_len-1;
- atomic_inc((atomic_t *)&prof_buffer[eip]);
-}
-
-static inline void hw_resend_irq(struct hw_interrupt_type *h,
- unsigned int i)
-{}
-
-#endif /* _ASM_HW_IRQ_H */
+++ /dev/null
-/******************************************************************************
- * hypervisor.h
- *
- * Linux-specific hypervisor handling.
- *
- * Copyright (c) 2002, K A Fraser
- */
-
-#ifndef __HYPERVISOR_H__
-#define __HYPERVISOR_H__
-
-#include <asm/hypervisor-ifs/hypervisor-if.h>
-#include <asm/ptrace.h>
-//#include <asm/page.h>
-
-/* arch/xeno/kernel/setup.c */
-union start_info_union
-{
- start_info_t start_info;
- char padding[512];
-};
-extern union start_info_union start_info_union;
-#define start_info (start_info_union.start_info)
-
-/* arch/xeno/kernel/hypervisor.c */
-void do_hypervisor_callback(struct pt_regs *regs);
-
-
-/* arch/xeno/mm/hypervisor.c */
-/*
- * NB. ptr values should be PHYSICAL, not MACHINE. 'vals' should be already
- * be MACHINE addresses.
- */
-
-extern unsigned int pt_update_queue_idx;
-
-void queue_l1_entry_update(unsigned long ptr, unsigned long val);
-void queue_l2_entry_update(unsigned long ptr, unsigned long val);
-void queue_pt_switch(unsigned long ptr);
-void queue_tlb_flush(void);
-void queue_invlpg(unsigned long ptr);
-void queue_pgd_pin(unsigned long ptr);
-void queue_pgd_unpin(unsigned long ptr);
-void queue_pte_pin(unsigned long ptr);
-void queue_pte_unpin(unsigned long ptr);
-void queue_set_ldt(unsigned long ptr, unsigned long bytes);
-#define PT_UPDATE_DEBUG 0
-
-#if PT_UPDATE_DEBUG > 0
-typedef struct {
- unsigned long ptr, val, pteval;
- void *ptep;
- int line; char *file;
-} page_update_debug_t;
-extern page_update_debug_t update_debug_queue[];
-#define queue_l1_entry_update(_p,_v) ({ \
- update_debug_queue[pt_update_queue_idx].ptr = (_p); \
- update_debug_queue[pt_update_queue_idx].val = (_v); \
- update_debug_queue[pt_update_queue_idx].line = __LINE__; \
- update_debug_queue[pt_update_queue_idx].file = __FILE__; \
- queue_l1_entry_update((_p),(_v)); \
-})
-#define queue_l2_entry_update(_p,_v) ({ \
- update_debug_queue[pt_update_queue_idx].ptr = (_p); \
- update_debug_queue[pt_update_queue_idx].val = (_v); \
- update_debug_queue[pt_update_queue_idx].line = __LINE__; \
- update_debug_queue[pt_update_queue_idx].file = __FILE__; \
- queue_l2_entry_update((_p),(_v)); \
-})
-#endif
-
-#if PT_UPDATE_DEBUG > 1
-#undef queue_l1_entry_update
-#undef queue_l2_entry_update
-#define queue_l1_entry_update(_p,_v) ({ \
- update_debug_queue[pt_update_queue_idx].ptr = (_p); \
- update_debug_queue[pt_update_queue_idx].val = (_v); \
- update_debug_queue[pt_update_queue_idx].line = __LINE__; \
- update_debug_queue[pt_update_queue_idx].file = __FILE__; \
- printk("L1 %s %d: %08lx (%08lx -> %08lx)\n", __FILE__, __LINE__, \
- phys_to_machine(_p), *(unsigned long *)__va(_p), \
- (unsigned long)(_v)); \
- queue_l1_entry_update((_p),(_v)); \
-})
-#define queue_l2_entry_update(_p,_v) ({ \
- update_debug_queue[pt_update_queue_idx].ptr = (_p); \
- update_debug_queue[pt_update_queue_idx].val = (_v); \
- update_debug_queue[pt_update_queue_idx].line = __LINE__; \
- update_debug_queue[pt_update_queue_idx].file = __FILE__; \
- printk("L2 %s %d: %08lx (%08lx -> %08lx)\n", __FILE__, __LINE__, \
- phys_to_machine(_p), *(unsigned long *)__va(_p), \
- (unsigned long)(_v)); \
- queue_l2_entry_update((_p),(_v)); \
-})
-#define queue_pt_switch(_p) ({ \
- printk("PTSWITCH %s %d: %08lx\n", __FILE__, __LINE__, (_p)); \
- queue_pt_switch(_p); \
-})
-#define queue_tlb_flush() ({ \
- printk("TLB FLUSH %s %d\n", __FILE__, __LINE__); \
- queue_tlb_flush(); \
-})
-#define queue_invlpg(_p) ({ \
- printk("INVLPG %s %d: %08lx\n", __FILE__, __LINE__, (_p)); \
- queue_invlpg(_p); \
-})
-#define queue_pgd_pin(_p) ({ \
- printk("PGD PIN %s %d: %08lx\n", __FILE__, __LINE__, (_p)); \
- queue_pgd_pin(_p); \
-})
-#define queue_pgd_unpin(_p) ({ \
- printk("PGD UNPIN %s %d: %08lx\n", __FILE__, __LINE__, (_p)); \
- queue_pgd_unpin(_p); \
-})
-#define queue_pte_pin(_p) ({ \
- printk("PTE PIN %s %d: %08lx\n", __FILE__, __LINE__, (_p)); \
- queue_pte_pin(_p); \
-})
-#define queue_pte_unpin(_p) ({ \
- printk("PTE UNPIN %s %d: %08lx\n", __FILE__, __LINE__, (_p)); \
- queue_pte_unpin(_p); \
-})
-#define queue_set_ldt(_p,_l) ({ \
- printk("SETL LDT %s %d: %08lx %d\n", __FILE__, __LINE__, (_p), (_l)); \
- queue_set_ldt((_p), (_l)); \
-})
-#endif
-
-void _flush_page_update_queue(void);
-static inline int flush_page_update_queue(void)
-{
- unsigned int idx = pt_update_queue_idx;
- if ( idx != 0 ) _flush_page_update_queue();
- return idx;
-}
-#define XENO_flush_page_update_queue() (_flush_page_update_queue())
-void MULTICALL_flush_page_update_queue(void);
-
-
-/*
- * Assembler stubs for hyper-calls.
- */
-
-static inline int HYPERVISOR_set_trap_table(trap_info_t *table)
-{
- int ret;
- __asm__ __volatile__ (
- TRAP_INSTR
- : "=a" (ret) : "0" (__HYPERVISOR_set_trap_table),
- "b" (table) );
-
- return ret;
-}
-
-
-static inline int HYPERVISOR_pt_update(page_update_request_t *req, int count)
-{
- int ret;
- __asm__ __volatile__ (
- TRAP_INSTR
- : "=a" (ret) : "0" (__HYPERVISOR_pt_update),
- "b" (req), "c" (count) );
-
- return ret;
-}
-
-
-static inline int HYPERVISOR_console_write(const char *str, int count)
-{
- int ret;
- __asm__ __volatile__ (
- TRAP_INSTR
- : "=a" (ret) : "0" (__HYPERVISOR_console_write),
- "b" (str), "c" (count) );
-
-
- return ret;
-}
-
-static inline int HYPERVISOR_set_gdt(unsigned long *frame_list, int entries)
-{
- int ret;
- __asm__ __volatile__ (
- TRAP_INSTR
- : "=a" (ret) : "0" (__HYPERVISOR_set_gdt),
- "b" (frame_list), "c" (entries) );
-
-
- return ret;
-}
-
-static inline int HYPERVISOR_stack_switch(unsigned long ss, unsigned long esp)
-{
- int ret;
- __asm__ __volatile__ (
- TRAP_INSTR
- : "=a" (ret) : "0" (__HYPERVISOR_stack_switch),
- "b" (ss), "c" (esp) : "memory" );
-
- return ret;
-}
-
-static inline int HYPERVISOR_set_callbacks(
- unsigned long event_selector, unsigned long event_address,
- unsigned long failsafe_selector, unsigned long failsafe_address)
-{
- int ret;
- __asm__ __volatile__ (
- TRAP_INSTR
- : "=a" (ret) : "0" (__HYPERVISOR_set_callbacks),
- "b" (event_selector), "c" (event_address),
- "d" (failsafe_selector), "S" (failsafe_address) : "memory" );
-
- return ret;
-}
-
-static inline int HYPERVISOR_net_update(void)
-{
- int ret;
- __asm__ __volatile__ (
- TRAP_INSTR
- : "=a" (ret) : "0" (__HYPERVISOR_net_update) );
-
- return ret;
-}
-
-static inline int HYPERVISOR_fpu_taskswitch(void)
-{
- int ret;
- __asm__ __volatile__ (
- TRAP_INSTR
- : "=a" (ret) : "0" (__HYPERVISOR_fpu_taskswitch) );
-
- return ret;
-}
-
-static inline int HYPERVISOR_yield(void)
-{
- int ret;
- __asm__ __volatile__ (
- TRAP_INSTR
- : "=a" (ret) : "0" (__HYPERVISOR_yield) );
-
- return ret;
-}
-
-static inline int HYPERVISOR_exit(void)
-{
- int ret;
- __asm__ __volatile__ (
- TRAP_INSTR
- : "=a" (ret) : "0" (__HYPERVISOR_exit) );
-
- return ret;
-}
-
-static inline int HYPERVISOR_dom0_op(void *dom0_op)
-{
- int ret;
- __asm__ __volatile__ (
- TRAP_INSTR
- : "=a" (ret) : "0" (__HYPERVISOR_dom0_op),
- "b" (dom0_op) : "memory" );
-
- return ret;
-}
-
-static inline int HYPERVISOR_network_op(void *network_op)
-{
- int ret;
- __asm__ __volatile__ (
- TRAP_INSTR
- : "=a" (ret) : "0" (__HYPERVISOR_network_op),
- "b" (network_op) );
-
- return ret;
-}
-
-static inline int HYPERVISOR_block_io_op(void)
-{
- int ret;
- __asm__ __volatile__ (
- TRAP_INSTR
- : "=a" (ret) : "0" (__HYPERVISOR_block_io_op) );
-
- return ret;
-}
-
-static inline int HYPERVISOR_set_debugreg(int reg, unsigned long value)
-{
- int ret;
- __asm__ __volatile__ (
- TRAP_INSTR
- : "=a" (ret) : "0" (__HYPERVISOR_set_debugreg),
- "b" (reg), "c" (value) );
-
- return ret;
-}
-
-static inline unsigned long HYPERVISOR_get_debugreg(int reg)
-{
- unsigned long ret;
- __asm__ __volatile__ (
- TRAP_INSTR
- : "=a" (ret) : "0" (__HYPERVISOR_get_debugreg),
- "b" (reg) );
-
- return ret;
-}
-
-static inline int HYPERVISOR_update_descriptor(
- unsigned long pa, unsigned long word1, unsigned long word2)
-{
- int ret;
- __asm__ __volatile__ (
- TRAP_INSTR
- : "=a" (ret) : "0" (__HYPERVISOR_update_descriptor),
- "b" (pa), "c" (word1), "d" (word2) );
-
- return ret;
-}
-
-static inline int HYPERVISOR_set_fast_trap(int idx)
-{
- int ret;
- __asm__ __volatile__ (
- TRAP_INSTR
- : "=a" (ret) : "0" (__HYPERVISOR_set_fast_trap),
- "b" (idx) );
-
- return ret;
-}
-
-static inline int HYPERVISOR_dom_mem_op(void *dom_mem_op)
-{
- int ret;
- __asm__ __volatile__ (
- TRAP_INSTR
- : "=a" (ret) : "0" (__HYPERVISOR_dom_mem_op),
- "b" (dom_mem_op) : "memory" );
-
- return ret;
-}
-
-static inline int HYPERVISOR_multicall(void *call_list, int nr_calls)
-{
- int ret;
- __asm__ __volatile__ (
- TRAP_INSTR
- : "=a" (ret) : "0" (__HYPERVISOR_multicall),
- "b" (call_list), "c" (nr_calls) : "memory" );
-
- return ret;
-}
-
-static inline long HYPERVISOR_kbd_op(unsigned char op, unsigned char val)
-{
- int ret;
- __asm__ __volatile__ (
- TRAP_INSTR
- : "=a" (ret) : "0" (__HYPERVISOR_kbd_op),
- "b" (op), "c" (val) );
-
- return ret;
-}
-
-static inline long HYPERVISOR_set_priv_levels(unsigned int new_io_pl,
- unsigned int new_hypercall_pl)
-{
- int ret;
- __asm__ __volatile__ (
- TRAP_INSTR
- : "=a" (ret) : "0" (__HYPERVISOR_set_priv_levels),
- "b" (new_io_pl), "c" (new_hypercall_pl) );
-
- return ret;
-}
-
-#endif /* __HYPERVISOR_H__ */
+++ /dev/null
-#ifndef _ASM_IO_H
-#define _ASM_IO_H
-
-#include <linux/config.h>
-#include <asm/hypervisor.h>
-/*
- * This file contains the definitions for the x86 IO instructions
- * inb/inw/inl/outb/outw/outl and the "string versions" of the same
- * (insb/insw/insl/outsb/outsw/outsl). You can also use "pausing"
- * versions of the single-IO instructions (inb_p/inw_p/..).
- *
- * This file is not meant to be obfuscating: it's just complicated
- * to (a) handle it all in a way that makes gcc able to optimize it
- * as well as possible and (b) trying to avoid writing the same thing
- * over and over again with slight variations and possibly making a
- * mistake somewhere.
- */
-
-/*
- * Thanks to James van Artsdalen for a better timing-fix than
- * the two short jumps: using outb's to a nonexistent port seems
- * to guarantee better timings even on fast machines.
- *
- * On the other hand, I'd like to be sure of a non-existent port:
- * I feel a bit unsafe about using 0x80 (should be safe, though)
- *
- * Linus
- */
-
- /*
- * Bit simplified and optimized by Jan Hubicka
- * Support of BIGMEM added by Gerhard Wichert, Siemens AG, July 1999.
- *
- * isa_memset_io, isa_memcpy_fromio, isa_memcpy_toio added,
- * isa_read[wl] and isa_write[wl] fixed
- * - Arnaldo Carvalho de Melo <acme@conectiva.com.br>
- */
-
-#define IO_SPACE_LIMIT 0xffff
-
-#define XQUAD_PORTIO_BASE 0xfe400000
-#define XQUAD_PORTIO_QUAD 0x40000 /* 256k per quad. */
-#define XQUAD_PORTIO_LEN 0x80000 /* Only remapping first 2 quads */
-
-#ifdef __KERNEL__
-
-#include <linux/vmalloc.h>
-
-/*
- * Temporary debugging check to catch old code using
- * unmapped ISA addresses. Will be removed in 2.4.
- */
-#if CONFIG_DEBUG_IOVIRT
- extern void *__io_virt_debug(unsigned long x, const char *file, int line);
- extern unsigned long __io_phys_debug(unsigned long x, const char *file, int line);
- #define __io_virt(x) __io_virt_debug((unsigned long)(x), __FILE__, __LINE__)
-//#define __io_phys(x) __io_phys_debug((unsigned long)(x), __FILE__, __LINE__)
-#else
- #define __io_virt(x) ((void *)(x))
-//#define __io_phys(x) __pa(x)
-#endif
-
-/**
- * virt_to_phys - map virtual addresses to physical
- * @address: address to remap
- *
- * The returned physical address is the physical (CPU) mapping for
- * the memory address given. It is only valid to use this function on
- * addresses directly mapped or allocated via kmalloc.
- *
- * This function does not give bus mappings for DMA transfers. In
- * almost all conceivable cases a device driver should not be using
- * this function
- */
-
-static inline unsigned long virt_to_phys(volatile void * address)
-{
- return __pa(address);
-}
-
-/**
- * phys_to_virt - map physical address to virtual
- * @address: address to remap
- *
- * The returned virtual address is a current CPU mapping for
- * the memory address given. It is only valid to use this function on
- * addresses that have a kernel mapping
- *
- * This function does not handle bus mappings for DMA transfers. In
- * almost all conceivable cases a device driver should not be using
- * this function
- */
-
-static inline void * phys_to_virt(unsigned long address)
-{
- return __va(address);
-}
-
-/*
- * Change "struct page" to physical address.
- */
-#ifdef CONFIG_HIGHMEM64G
-#define page_to_phys(page) ((u64)(page - mem_map) << PAGE_SHIFT)
-#else
-#define page_to_phys(page) ((page - mem_map) << PAGE_SHIFT)
-#endif
-
-/*
- * IO bus memory addresses are also 1:1 with the physical address
- */
-#define virt_to_bus virt_to_phys
-#define bus_to_virt phys_to_virt
-#define page_to_bus page_to_phys
-
-/*
- * readX/writeX() are used to access memory mapped devices. On some
- * architectures the memory mapped IO stuff needs to be accessed
- * differently. On the x86 architecture, we just read/write the
- * memory location directly.
- */
-
-#define readb(addr) (*(volatile unsigned char *) __io_virt(addr))
-#define readw(addr) (*(volatile unsigned short *) __io_virt(addr))
-#define readl(addr) (*(volatile unsigned int *) __io_virt(addr))
-#define __raw_readb readb
-#define __raw_readw readw
-#define __raw_readl readl
-
-#define writeb(b,addr) (*(volatile unsigned char *) __io_virt(addr) = (b))
-#define writew(b,addr) (*(volatile unsigned short *) __io_virt(addr) = (b))
-#define writel(b,addr) (*(volatile unsigned int *) __io_virt(addr) = (b))
-#define __raw_writeb writeb
-#define __raw_writew writew
-#define __raw_writel writel
-
-#define memset_io(a,b,c) __memset(__io_virt(a),(b),(c))
-#define memcpy_fromio(a,b,c) __memcpy((a),__io_virt(b),(c))
-#define memcpy_toio(a,b,c) __memcpy(__io_virt(a),(b),(c))
-
-/*
- * ISA space is 'always mapped' on a typical x86 system, no need to
- * explicitly ioremap() it. The fact that the ISA IO space is mapped
- * to PAGE_OFFSET is pure coincidence - it does not mean ISA values
- * are physical addresses. The following constant pointer can be
- * used as the IO-area pointer (it can be iounmapped as well, so the
- * analogy with PCI is quite large):
- */
-#define __ISA_IO_base ((char *)(PAGE_OFFSET))
-
-#define isa_readb(a) readb(__ISA_IO_base + (a))
-#define isa_readw(a) readw(__ISA_IO_base + (a))
-#define isa_readl(a) readl(__ISA_IO_base + (a))
-#define isa_writeb(b,a) writeb(b,__ISA_IO_base + (a))
-#define isa_writew(w,a) writew(w,__ISA_IO_base + (a))
-#define isa_writel(l,a) writel(l,__ISA_IO_base + (a))
-#define isa_memset_io(a,b,c) memset_io(__ISA_IO_base + (a),(b),(c))
-#define isa_memcpy_fromio(a,b,c) memcpy_fromio((a),__ISA_IO_base + (b),(c))
-#define isa_memcpy_toio(a,b,c) memcpy_toio(__ISA_IO_base + (a),(b),(c))
-
-
-/*
- * Again, i386 does not require mem IO specific function.
- */
-
-#define eth_io_copy_and_sum(a,b,c,d) eth_copy_and_sum((a),__io_virt(b),(c),(d))
-#define isa_eth_io_copy_and_sum(a,b,c,d) eth_copy_and_sum((a),__io_virt(__ISA_IO_base + (b)),(c),(d))
-
-/**
- * check_signature - find BIOS signatures
- * @io_addr: mmio address to check
- * @signature: signature block
- * @length: length of signature
- *
- * Perform a signature comparison with the mmio address io_addr. This
- * address should have been obtained by ioremap.
- * Returns 1 on a match.
- */
-
-static inline int check_signature(unsigned long io_addr,
- const unsigned char *signature, int length)
-{
- int retval = 0;
- do {
- if (readb(io_addr) != *signature)
- goto out;
- io_addr++;
- signature++;
- length--;
- } while (length);
- retval = 1;
-out:
- return retval;
-}
-
-/**
- * isa_check_signature - find BIOS signatures
- * @io_addr: mmio address to check
- * @signature: signature block
- * @length: length of signature
- *
- * Perform a signature comparison with the ISA mmio address io_addr.
- * Returns 1 on a match.
- *
- * This function is deprecated. New drivers should use ioremap and
- * check_signature.
- */
-
-
-static inline int isa_check_signature(unsigned long io_addr,
- const unsigned char *signature, int length)
-{
- int retval = 0;
- do {
- if (isa_readb(io_addr) != *signature)
- goto out;
- io_addr++;
- signature++;
- length--;
- } while (length);
- retval = 1;
-out:
- return retval;
-}
-
-/*
- * Cache management
- *
- * This needed for two cases
- * 1. Out of order aware processors
- * 2. Accidentally out of order processors (PPro errata #51)
- */
-
-#if defined(CONFIG_X86_OOSTORE) || defined(CONFIG_X86_PPRO_FENCE)
-
-static inline void flush_write_buffers(void)
-{
- __asm__ __volatile__ ("lock; addl $0,0(%%esp)": : :"memory");
-}
-
-#define dma_cache_inv(_start,_size) flush_write_buffers()
-#define dma_cache_wback(_start,_size) flush_write_buffers()
-#define dma_cache_wback_inv(_start,_size) flush_write_buffers()
-
-#else
-
-/* Nothing to do */
-
-#define dma_cache_inv(_start,_size) do { } while (0)
-#define dma_cache_wback(_start,_size) do { } while (0)
-#define dma_cache_wback_inv(_start,_size) do { } while (0)
-#define flush_write_buffers()
-
-#endif
-
-#endif /* __KERNEL__ */
-
-#ifdef SLOW_IO_BY_JUMPING
-#define __SLOW_DOWN_IO "\njmp 1f\n1:\tjmp 1f\n1:"
-#else
-#define __SLOW_DOWN_IO "\noutb %%al,$0x80"
-#endif
-
-#ifdef REALLY_SLOW_IO
-#define __FULL_SLOW_DOWN_IO __SLOW_DOWN_IO __SLOW_DOWN_IO __SLOW_DOWN_IO __SLOW_DOWN_IO
-#else
-#define __FULL_SLOW_DOWN_IO __SLOW_DOWN_IO
-#endif
-
-#ifdef CONFIG_MULTIQUAD
-extern void *xquad_portio; /* Where the IO area was mapped */
-#endif /* CONFIG_MULTIQUAD */
-
-/*
- * Talk about misusing macros..
- */
-#define __OUT1(s,x) \
-static inline void out##s(unsigned x value, unsigned short port) {
-
-#define __OUT2(s,s1,s2) \
-__asm__ __volatile__ ("out" #s " %" s1 "0,%" s2 "1"
-
-#if defined (CONFIG_MULTIQUAD) && !defined(STANDALONE)
-#define __OUTQ(s,ss,x) /* Do the equivalent of the portio op on quads */ \
-static inline void out##ss(unsigned x value, unsigned short port) { \
- if (xquad_portio) \
- write##s(value, (unsigned long) xquad_portio + port); \
- else /* We're still in early boot, running on quad 0 */ \
- out##ss##_local(value, port); \
-} \
-static inline void out##ss##_quad(unsigned x value, unsigned short port, int quad) { \
- if (xquad_portio) \
- write##s(value, (unsigned long) xquad_portio + (XQUAD_PORTIO_QUAD*quad)\
- + port); \
-}
-
-#define __INQ(s,ss) /* Do the equivalent of the portio op on quads */ \
-static inline RETURN_TYPE in##ss(unsigned short port) { \
- if (xquad_portio) \
- return read##s((unsigned long) xquad_portio + port); \
- else /* We're still in early boot, running on quad 0 */ \
- return in##ss##_local(port); \
-} \
-static inline RETURN_TYPE in##ss##_quad(unsigned short port, int quad) { \
- if (xquad_portio) \
- return read##s((unsigned long) xquad_portio + (XQUAD_PORTIO_QUAD*quad)\
- + port); \
- else\
- return 0;\
-}
-#endif /* CONFIG_MULTIQUAD && !STANDALONE */
-
-#if !defined(CONFIG_MULTIQUAD) || defined(STANDALONE)
-#define __OUT(s,s1,x) \
-__OUT1(s,x) __OUT2(s,s1,"w") : : "a" (value), "Nd" (port)); } \
-__OUT1(s##_p,x) __OUT2(s,s1,"w") __FULL_SLOW_DOWN_IO : : "a" (value), "Nd" (port));}
-#else
-/* Make the default portio routines operate on quad 0 */
-#define __OUT(s,s1,x) \
-__OUT1(s##_local,x) __OUT2(s,s1,"w") : : "a" (value), "Nd" (port)); } \
-__OUT1(s##_p_local,x) __OUT2(s,s1,"w") __FULL_SLOW_DOWN_IO : : "a" (value), "Nd" (port));} \
-__OUTQ(s,s,x) \
-__OUTQ(s,s##_p,x)
-#endif /* !CONFIG_MULTIQUAD || STANDALONE */
-
-#define __IN1(s) \
-static inline RETURN_TYPE in##s(unsigned short port) { RETURN_TYPE _v;
-
-#define __IN2(s,s1,s2) \
-__asm__ __volatile__ ("in" #s " %" s2 "1,%" s1 "0"
-
-#if !defined(CONFIG_MULTIQUAD) || defined(STANDALONE)
-#define __IN(s,s1,i...) \
-__IN1(s) __IN2(s,s1,"w") : "=a" (_v) : "Nd" (port) ,##i ); return _v; } \
-__IN1(s##_p) __IN2(s,s1,"w") __FULL_SLOW_DOWN_IO : "=a" (_v) : "Nd" (port) ,##i ); return _v; }
-#else
-/* Make the default portio routines operate on quad 0 */
-#define __IN(s,s1,i...) \
-__IN1(s##_local) __IN2(s,s1,"w") : "=a" (_v) : "Nd" (port) ,##i ); return _v; } \
-__IN1(s##_p_local) __IN2(s,s1,"w") __FULL_SLOW_DOWN_IO : "=a" (_v) : "Nd" (port) ,##i ); return _v; } \
-__INQ(s,s) \
-__INQ(s,s##_p)
-#endif /* !CONFIG_MULTIQUAD || STANDALONE */
-
-#define __INS(s) \
-static inline void ins##s(unsigned short port, void * addr, unsigned long count) \
-{ __asm__ __volatile__ ("rep ; ins" #s \
-: "=D" (addr), "=c" (count) : "d" (port),"0" (addr),"1" (count)); }
-
-#define __OUTS(s) \
-static inline void outs##s(unsigned short port, const void * addr, unsigned long count) \
-{ __asm__ __volatile__ ("rep ; outs" #s \
-: "=S" (addr), "=c" (count) : "d" (port),"0" (addr),"1" (count)); }
-
-#define RETURN_TYPE unsigned char
-__IN(b,"")
-#undef RETURN_TYPE
-#define RETURN_TYPE unsigned short
-__IN(w,"")
-#undef RETURN_TYPE
-#define RETURN_TYPE unsigned int
-__IN(l,"")
-#undef RETURN_TYPE
-
-__OUT(b,"b",char)
-__OUT(w,"w",short)
-__OUT(l,,int)
-
-__INS(b)
-__INS(w)
-__INS(l)
-
-__OUTS(b)
-__OUTS(w)
-__OUTS(l)
-
-#endif
+++ /dev/null
-#ifndef _ASM_IRQ_H
-#define _ASM_IRQ_H
-
-/*
- * linux/include/asm/irq.h
- *
- * (C) 1992, 1993 Linus Torvalds, (C) 1997 Ingo Molnar
- *
- * IRQ/IPI changes taken from work by Thomas Radke
- * <tomsoft@informatik.tu-chemnitz.de>
- */
-
-#include <linux/config.h>
-#include <asm/hypervisor.h>
-#include <asm/ptrace.h>
-
-#define NET_TX_IRQ _EVENT_NET_TX
-#define NET_RX_IRQ _EVENT_NET_RX
-#define NET2_TX_IRQ _EVENT_NET2_TX
-#define NET2_RX_IRQ _EVENT_NET2_RX
-#define TIMER_IRQ _EVENT_TIMER
-
-#define NR_IRQS (sizeof(HYPERVISOR_shared_info->events) * 8)
-
-#define irq_cannonicalize(_irq) (_irq)
-
-extern void disable_irq(unsigned int);
-extern void disable_irq_nosync(unsigned int);
-extern void enable_irq(unsigned int);
-
-#ifdef CONFIG_X86_LOCAL_APIC
-#define ARCH_HAS_NMI_WATCHDOG /* See include/linux/nmi.h */
-#endif
-
-#endif /* _ASM_IRQ_H */
+++ /dev/null
-/* xenolinux/include/asm-xeno/keyboard.h */
-/* Portions copyright (c) 2003 James Scott, Intel Research Cambridge */
-/* Talks to hypervisor to get PS/2 keyboard and mouse events, and send keyboard and mouse commands */
-
-/* Based on:
- * linux/include/asm-i386/keyboard.h
- *
- * Created 3 Nov 1996 by Geert Uytterhoeven
- */
-
-#ifndef _XENO_KEYBOARD_H
-#define _XENO_KEYBOARD_H
-
-#ifdef __KERNEL__
-
-#include <linux/kernel.h>
-#include <linux/ioport.h>
-#include <linux/kd.h>
-#include <linux/pm.h>
-#include <asm/io.h>
-
-
-#define KEYBOARD_IRQ _EVENT_KBD
-#define AUX_IRQ _EVENT_KBD
-
-/* THIS SECTION RELATIVELY UNTOUCHED */
-
-extern int pckbd_setkeycode(unsigned int scancode, unsigned int keycode);
-extern int pckbd_getkeycode(unsigned int scancode);
-extern int pckbd_translate(unsigned char scancode, unsigned char *keycode,
- char raw_mode);
-extern char pckbd_unexpected_up(unsigned char keycode);
-extern void pckbd_leds(unsigned char leds);
-extern void pckbd_init_hw(void);
-extern int pckbd_pm_resume(struct pm_dev *, pm_request_t, void *);
-
-extern pm_callback pm_kbd_request_override;
-extern unsigned char pckbd_sysrq_xlate[128];
-
-#define kbd_setkeycode pckbd_setkeycode
-#define kbd_getkeycode pckbd_getkeycode
-#define kbd_translate pckbd_translate
-#define kbd_unexpected_up pckbd_unexpected_up
-#define kbd_leds pckbd_leds
-#define kbd_init_hw pckbd_init_hw
-#define kbd_sysrq_xlate pckbd_sysrq_xlate
-
-#define SYSRQ_KEY 0x54
-
-
-/* THIS SECTION TALKS TO XEN TO DO PS2 SUPPORT */
-#include <asm/hypervisor-ifs/kbd.h>
-#include <asm/hypervisor-ifs/hypervisor-if.h>
-
-/* resource allocation */
-#define kbd_request_region() do { } while (0)
-#define kbd_request_irq(handler) request_irq(_EVENT_KBD, handler, 0, "PS/2 kbd", NULL)
-
-// could implement these with command to xen to filter mouse stuff...
-#define aux_request_irq(hand, dev_id) 0
-#define aux_free_irq(dev_id) do { } while(0)
-
-/* Some stoneage hardware needs delays after some operations. */
-#define kbd_pause() do { } while(0)
-
-
-static unsigned char kbd_current_scancode = 0;
-
-static unsigned char kbd_read_input(void)
-{
- //printk("kbd_read_input: returning scancode 0x%2x\n", kbd_current_scancode);
- return kbd_current_scancode;
-}
-
-static unsigned char kbd_read_status(void)
-{
- long res;
- res = HYPERVISOR_kbd_op(KBD_OP_READ,0);
- if(res<0) {
- //printk("kbd_read_status: error from hypervisor: %d", res);
- kbd_current_scancode = 0;
- return 0; // error with our request - wrong domain?
- }
- kbd_current_scancode = KBD_CODE_SCANCODE(res);
- //printk("kbd_read_status: returning status 0x%2x\n", KBD_CODE_STATUS(res));
- return KBD_CODE_STATUS(res);
-}
-
-
-#define kbd_write_output(val) HYPERVISOR_kbd_op(KBD_OP_WRITEOUTPUT, val);
-#define kbd_write_command(val) HYPERVISOR_kbd_op(KBD_OP_WRITECOMMAND, val);
-
-
-#endif /* __KERNEL__ */
-#endif /* _XENO_KEYBOARD_H */
+++ /dev/null
-#ifndef __i386_MMU_H
-#define __i386_MMU_H
-
-#include <linux/list.h>
-
-/* describes dirrectly mapped vma nodes */
-typedef struct {
- struct list_head list;
- unsigned long vm_start;
- unsigned long vm_end;
-} direct_mmap_node_t;
-
-/*
- * The i386 doesn't have a mmu context, but
- * we put the segment information here.
- */
-typedef struct {
- void *segments;
- unsigned long cpuvalid;
- struct list_head direct_list;
-} mm_context_t;
-
-#endif
+++ /dev/null
-#ifndef __I386_MMU_CONTEXT_H
-#define __I386_MMU_CONTEXT_H
-
-#include <linux/config.h>
-#include <asm/desc.h>
-#include <asm/atomic.h>
-#include <asm/pgalloc.h>
-#include <asm/multicall.h>
-
-/*
- * possibly do the LDT unload here?
- */
-
-extern int init_new_context(struct task_struct *tsk, struct mm_struct *);
-extern void destroy_context(struct mm_struct *);
-
-//#define destroy_context(mm) do { } while(0)
-//#define init_new_context(tsk,mm) 0
-
-#ifdef CONFIG_SMP
-
-static inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk, unsigned cpu)
-{
- if(cpu_tlbstate[cpu].state == TLBSTATE_OK)
- cpu_tlbstate[cpu].state = TLBSTATE_LAZY;
-}
-#else
-static inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk, unsigned cpu)
-{
-}
-#endif
-
-extern pgd_t *cur_pgd;
-
-static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next, struct task_struct *tsk, unsigned cpu)
-{
- if (prev != next) {
- /* stop flush ipis for the previous mm */
- clear_bit(cpu, &prev->cpu_vm_mask);
- /*
- * Re-load LDT if necessary
- */
- if (prev->context.segments != next->context.segments)
- load_LDT(next);
-#ifdef CONFIG_SMP
- cpu_tlbstate[cpu].state = TLBSTATE_OK;
- cpu_tlbstate[cpu].active_mm = next;
-#endif
- set_bit(cpu, &next->cpu_vm_mask);
- set_bit(cpu, &next->context.cpuvalid);
- /* Re-load page tables */
- cur_pgd = next->pgd;
- queue_pt_switch(__pa(cur_pgd));
- }
-#ifdef CONFIG_SMP
- else {
- cpu_tlbstate[cpu].state = TLBSTATE_OK;
- if(cpu_tlbstate[cpu].active_mm != next)
- out_of_line_bug();
- if(!test_and_set_bit(cpu, &next->cpu_vm_mask)) {
- /* We were in lazy tlb mode and leave_mm disabled
- * tlb flush IPI delivery. We must reload %cr3.
- */
- load_cr3(next->pgd);
- }
- if (!test_and_set_bit(cpu, &next->context.cpuvalid))
- load_LDT(next);
- }
-#endif
-}
-
-#define activate_mm(prev, next) \
-do { \
- switch_mm((prev),(next),NULL,smp_processor_id()); \
- flush_page_update_queue(); \
-} while ( 0 )
-
-#endif
+++ /dev/null
-/******************************************************************************
- * multicall.h
- */
-
-#ifndef __MULTICALL_H__
-#define __MULTICALL_H__
-
-#include <asm/hypervisor.h>
-
-extern multicall_entry_t multicall_list[];
-extern int nr_multicall_ents;
-
-static inline void queue_multicall0(unsigned long op)
-{
- int i = nr_multicall_ents;
- multicall_list[i].op = op;
- nr_multicall_ents = i+1;
-}
-
-static inline void queue_multicall1(unsigned long op, unsigned long arg1)
-{
- int i = nr_multicall_ents;
- multicall_list[i].op = op;
- multicall_list[i].args[0] = arg1;
- nr_multicall_ents = i+1;
-}
-
-static inline void queue_multicall2(
- unsigned long op, unsigned long arg1, unsigned long arg2)
-{
- int i = nr_multicall_ents;
- multicall_list[i].op = op;
- multicall_list[i].args[0] = arg1;
- multicall_list[i].args[1] = arg2;
- nr_multicall_ents = i+1;
-}
-
-static inline void execute_multicall_list(void)
-{
- if ( unlikely(nr_multicall_ents == 0) ) return;
- (void)HYPERVISOR_multicall(multicall_list, nr_multicall_ents);
- nr_multicall_ents = 0;
-}
-
-#endif /* __MULTICALL_H__ */
+++ /dev/null
-#ifndef _I386_PAGE_H
-#define _I386_PAGE_H
-
-/* PAGE_SHIFT determines the page size */
-#define PAGE_SHIFT 12
-#define PAGE_SIZE (1UL << PAGE_SHIFT)
-#define PAGE_MASK (~(PAGE_SIZE-1))
-
-#ifdef __KERNEL__
-#ifndef __ASSEMBLY__
-
-#include <linux/config.h>
-#include <asm/hypervisor.h>
-
-#ifdef CONFIG_X86_USE_3DNOW
-
-#include <asm/mmx.h>
-
-#define clear_page(page) mmx_clear_page((void *)(page))
-#define copy_page(to,from) mmx_copy_page(to,from)
-
-#else
-
-/*
- * On older X86 processors its not a win to use MMX here it seems.
- * Maybe the K6-III ?
- */
-
-#define clear_page(page) memset((void *)(page), 0, PAGE_SIZE)
-#define copy_page(to,from) memcpy((void *)(to), (void *)(from), PAGE_SIZE)
-
-#endif
-
-#define clear_user_page(page, vaddr) clear_page(page)
-#define copy_user_page(to, from, vaddr) copy_page(to, from)
-
-/**** MACHINE <-> PHYSICAL CONVERSION MACROS ****/
-extern unsigned long *phys_to_machine_mapping;
-#define pfn_to_mfn(_pfn) (phys_to_machine_mapping[(_pfn)])
-#define mfn_to_pfn(_mfn) (machine_to_phys_mapping[(_mfn)])
-static inline unsigned long phys_to_machine(unsigned long phys)
-{
- unsigned long machine = pfn_to_mfn(phys >> PAGE_SHIFT);
- machine = (machine << PAGE_SHIFT) | (phys & ~PAGE_MASK);
- return machine;
-}
-static inline unsigned long machine_to_phys(unsigned long machine)
-{
- unsigned long phys = mfn_to_pfn(machine >> PAGE_SHIFT);
- phys = (phys << PAGE_SHIFT) | (machine & ~PAGE_MASK);
- return phys;
-}
-
-/*
- * These are used to make use of C type-checking..
- */
-#if CONFIG_X86_PAE
-typedef struct { unsigned long pte_low, pte_high; } pte_t;
-typedef struct { unsigned long long pmd; } pmd_t;
-typedef struct { unsigned long long pgd; } pgd_t;
-#define pte_val(x) ((x).pte_low | ((unsigned long long)(x).pte_high << 32))
-#else
-typedef struct { unsigned long pte_low; } pte_t;
-typedef struct { unsigned long pmd; } pmd_t;
-typedef struct { unsigned long pgd; } pgd_t;
-static inline unsigned long pte_val(pte_t x)
-{
- unsigned long ret = x.pte_low;
- if ( (ret & 1) ) ret = machine_to_phys(ret);
- return ret;
-}
-#endif
-#define PTE_MASK PAGE_MASK
-
-typedef struct { unsigned long pgprot; } pgprot_t;
-
-static inline unsigned long pmd_val(pmd_t x)
-{
- unsigned long ret = x.pmd;
- if ( (ret & 1) ) ret = machine_to_phys(ret);
- return ret;
-}
-#define pgd_val(x) ({ BUG(); (unsigned long)0; })
-#define pgprot_val(x) ((x).pgprot)
-
-static inline pte_t __pte(unsigned long x)
-{
- if ( (x & 1) ) x = phys_to_machine(x);
- return ((pte_t) { (x) });
-}
-static inline pmd_t __pmd(unsigned long x)
-{
- if ( (x & 1) ) x = phys_to_machine(x);
- return ((pmd_t) { (x) });
-}
-#define __pgd(x) ({ BUG(); (pgprot_t) { 0 }; })
-#define __pgprot(x) ((pgprot_t) { (x) } )
-
-#endif /* !__ASSEMBLY__ */
-
-/* to align the pointer to the (next) page boundary */
-#define PAGE_ALIGN(addr) (((addr)+PAGE_SIZE-1)&PAGE_MASK)
-
-/*
- * This handles the memory map.. We could make this a config
- * option, but too many people screw it up, and too few need
- * it.
- *
- * A __PAGE_OFFSET of 0xC0000000 means that the kernel has
- * a virtual address space of one gigabyte, which limits the
- * amount of physical memory you can use to about 950MB.
- *
- * If you want more physical memory than this then see the CONFIG_HIGHMEM4G
- * and CONFIG_HIGHMEM64G options in the kernel configuration.
- */
-
-#define __PAGE_OFFSET (0xC0000000)
-
-#ifndef __ASSEMBLY__
-
-/*
- * Tell the user there is some problem. Beep too, so we can
- * see^H^H^Hhear bugs in early bootup as well!
- * The offending file and line are encoded after the "officially
- * undefined" opcode for parsing in the trap handler.
- */
-
-#if 1 /* Set to zero for a slightly smaller kernel */
-#define BUG() \
- __asm__ __volatile__( "ud2\n" \
- "\t.word %c0\n" \
- "\t.long %c1\n" \
- : : "i" (__LINE__), "i" (__FILE__))
-#else
-#define BUG() __asm__ __volatile__("ud2\n")
-#endif
-
-#define PAGE_BUG(page) do { \
- BUG(); \
-} while (0)
-
-/* Pure 2^n version of get_order */
-static __inline__ int get_order(unsigned long size)
-{
- int order;
-
- size = (size-1) >> (PAGE_SHIFT-1);
- order = -1;
- do {
- size >>= 1;
- order++;
- } while (size);
- return order;
-}
-
-#endif /* __ASSEMBLY__ */
-
-#define PAGE_OFFSET ((unsigned long)__PAGE_OFFSET)
-#define __pa(x) ((unsigned long)(x)-PAGE_OFFSET)
-#define __va(x) ((void *)((unsigned long)(x)+PAGE_OFFSET))
-#define virt_to_page(kaddr) (mem_map + (__pa(kaddr) >> PAGE_SHIFT))
-#define VALID_PAGE(page) ((page - mem_map) < max_mapnr)
-
-#define VM_DATA_DEFAULT_FLAGS (VM_READ | VM_WRITE | VM_EXEC | \
- VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC)
-
-/* VIRT <-> MACHINE conversion */
-#define virt_to_machine(_a) (phys_to_machine(__pa(_a)))
-#define machine_to_virt(_m) (__va(machine_to_phys(_m)))
-
-#endif /* __KERNEL__ */
-
-#endif /* _I386_PAGE_H */
+++ /dev/null
-#ifndef _I386_PGALLOC_H
-#define _I386_PGALLOC_H
-
-#include <linux/config.h>
-#include <asm/processor.h>
-#include <asm/fixmap.h>
-#include <asm/hypervisor.h>
-#include <linux/threads.h>
-
-/*
- * Quick lists are aligned so that least significant bits of array pointer
- * are all zero when list is empty, and all one when list is full.
- */
-#define QUICKLIST_ENTRIES 256
-#define QUICKLIST_EMPTY(_l) !((unsigned long)(_l) & ((QUICKLIST_ENTRIES*4)-1))
-#define QUICKLIST_FULL(_l) QUICKLIST_EMPTY((_l)+1)
-#define pgd_quicklist (current_cpu_data.pgd_quick)
-#define pmd_quicklist (current_cpu_data.pmd_quick)
-#define pte_quicklist (current_cpu_data.pte_quick)
-#define pgtable_cache_size (current_cpu_data.pgtable_cache_sz)
-
-#define pmd_populate(mm, pmd, pte) \
- do { \
- set_pmd(pmd, __pmd(_PAGE_TABLE + __pa(pte))); \
- XENO_flush_page_update_queue(); \
- } while ( 0 )
-
-/*
- * Allocate and free page tables.
- */
-
-#if defined (CONFIG_X86_PAE)
-
-#error "no PAE support as yet"
-
-/*
- * We can't include <linux/slab.h> here, thus these uglinesses.
- */
-struct kmem_cache_s;
-
-extern struct kmem_cache_s *pae_pgd_cachep;
-extern void *kmem_cache_alloc(struct kmem_cache_s *, int);
-extern void kmem_cache_free(struct kmem_cache_s *, void *);
-
-
-static inline pgd_t *get_pgd_slow(void)
-{
- int i;
- pgd_t *pgd = kmem_cache_alloc(pae_pgd_cachep, GFP_KERNEL);
-
- if (pgd) {
- for (i = 0; i < USER_PTRS_PER_PGD; i++) {
- unsigned long pmd = __get_free_page(GFP_KERNEL);
- if (!pmd)
- goto out_oom;
- clear_page(pmd);
- set_pgd(pgd + i, __pgd(1 + __pa(pmd)));
- }
- memcpy(pgd + USER_PTRS_PER_PGD,
- swapper_pg_dir + USER_PTRS_PER_PGD,
- (PTRS_PER_PGD - USER_PTRS_PER_PGD) * sizeof(pgd_t));
- }
- return pgd;
-out_oom:
- for (i--; i >= 0; i--)
- free_page((unsigned long)__va(pgd_val(pgd[i])-1));
- kmem_cache_free(pae_pgd_cachep, pgd);
- return NULL;
-}
-
-#else
-
-static inline pgd_t *get_pgd_slow(void)
-{
- pgd_t *pgd = (pgd_t *)__get_free_page(GFP_KERNEL);
-
- if (pgd) {
- memset(pgd, 0, USER_PTRS_PER_PGD * sizeof(pgd_t));
- memcpy(pgd + USER_PTRS_PER_PGD,
- init_mm.pgd + USER_PTRS_PER_PGD,
- (PTRS_PER_PGD - USER_PTRS_PER_PGD) * sizeof(pgd_t));
- __make_page_readonly(pgd);
- queue_pgd_pin(__pa(pgd));
-
- }
- return pgd;
-}
-
-#endif /* CONFIG_X86_PAE */
-
-static inline pgd_t *get_pgd_fast(void)
-{
- unsigned long ret;
-
- if ( !QUICKLIST_EMPTY(pgd_quicklist) ) {
- ret = *(--pgd_quicklist);
- pgtable_cache_size--;
-
- } else
- ret = (unsigned long)get_pgd_slow();
- return (pgd_t *)ret;
-}
-
-static inline void free_pgd_slow(pgd_t *pgd)
-{
-#if defined(CONFIG_X86_PAE)
-#error
- int i;
-
- for (i = 0; i < USER_PTRS_PER_PGD; i++)
- free_page((unsigned long)__va(pgd_val(pgd[i])-1));
- kmem_cache_free(pae_pgd_cachep, pgd);
-#else
- queue_pgd_unpin(__pa(pgd));
- __make_page_writeable(pgd);
- free_page((unsigned long)pgd);
-#endif
-}
-
-static inline void free_pgd_fast(pgd_t *pgd)
-{
- if ( !QUICKLIST_FULL(pgd_quicklist) ) {
- *(pgd_quicklist++) = (unsigned long)pgd;
- pgtable_cache_size++;
- } else
- free_pgd_slow(pgd);
-}
-
-static inline pte_t *pte_alloc_one(struct mm_struct *mm, unsigned long address)
-{
- pte_t *pte;
-
- pte = (pte_t *) __get_free_page(GFP_KERNEL);
- if (pte)
- {
- clear_page(pte);
- __make_page_readonly(pte);
- queue_pte_pin(__pa(pte));
- }
- return pte;
-
-}
-
-static inline pte_t *pte_alloc_one_fast(struct mm_struct *mm,
- unsigned long address)
-{
- unsigned long ret = 0;
- if ( !QUICKLIST_EMPTY(pte_quicklist) ) {
- ret = *(--pte_quicklist);
- pgtable_cache_size--;
- }
- return (pte_t *)ret;
-}
-
-static __inline__ void pte_free_slow(pte_t *pte)
-{
- queue_pte_unpin(__pa(pte));
- __make_page_writeable(pte);
- free_page((unsigned long)pte);
-}
-
-static inline void pte_free_fast(pte_t *pte)
-{
- if ( !QUICKLIST_FULL(pte_quicklist) ) {
- *(pte_quicklist++) = (unsigned long)pte;
- pgtable_cache_size++;
- } else
- pte_free_slow(pte);
-}
-
-#define pte_free(pte) pte_free_fast(pte)
-#define pgd_free(pgd) free_pgd_fast(pgd)
-#define pgd_alloc(mm) get_pgd_fast()
-
-/*
- * allocating and freeing a pmd is trivial: the 1-entry pmd is
- * inside the pgd, so has no extra memory associated with it.
- * (In the PAE case we free the pmds as part of the pgd.)
- */
-
-#define pmd_alloc_one_fast(mm, addr) ({ BUG(); ((pmd_t *)1); })
-#define pmd_alloc_one(mm, addr) ({ BUG(); ((pmd_t *)2); })
-#define pmd_free_slow(x) do { } while (0)
-#define pmd_free_fast(x) do { } while (0)
-#define pmd_free(x) do { } while (0)
-#define pgd_populate(mm, pmd, pte) BUG()
-
-extern int do_check_pgt_cache(int, int);
-
-/*
- * TLB flushing:
- *
- * - flush_tlb() flushes the current mm struct TLBs
- * - flush_tlb_all() flushes all processes TLBs
- * - flush_tlb_mm(mm) flushes the specified mm context TLB's
- * - flush_tlb_page(vma, vmaddr) flushes one page
- * - flush_tlb_range(mm, start, end) flushes a range of pages
- * - flush_tlb_pgtables(mm, start, end) flushes a range of page tables
- *
- * ..but the i386 has somewhat limited tlb flushing capabilities,
- * and page-granular flushes are available only on i486 and up.
- */
-
-#ifndef CONFIG_SMP
-
-#define flush_tlb() __flush_tlb()
-#define flush_tlb_all() __flush_tlb_all()
-#define local_flush_tlb() __flush_tlb()
-
-static inline void flush_tlb_mm(struct mm_struct *mm)
-{
- if (mm == current->active_mm) queue_tlb_flush();
- XENO_flush_page_update_queue();
-}
-
-static inline void flush_tlb_page(struct vm_area_struct *vma,
- unsigned long addr)
-{
- if (vma->vm_mm == current->active_mm) queue_invlpg(addr);
- XENO_flush_page_update_queue();
-}
-
-static inline void flush_tlb_range(struct mm_struct *mm,
- unsigned long start, unsigned long end)
-{
- if (mm == current->active_mm) queue_tlb_flush();
- XENO_flush_page_update_queue();
-}
-
-#else
-#error no guestos SMP support yet...
-#include <asm/smp.h>
-
-#define local_flush_tlb() \
- __flush_tlb()
-
-extern void flush_tlb_all(void);
-extern void flush_tlb_current_task(void);
-extern void flush_tlb_mm(struct mm_struct *);
-extern void flush_tlb_page(struct vm_area_struct *, unsigned long);
-
-#define flush_tlb() flush_tlb_current_task()
-
-static inline void flush_tlb_range(struct mm_struct * mm, unsigned long start, unsigned long end)
-{
- flush_tlb_mm(mm);
-}
-
-#define TLBSTATE_OK 1
-#define TLBSTATE_LAZY 2
-
-struct tlb_state
-{
- struct mm_struct *active_mm;
- int state;
-};
-extern struct tlb_state cpu_tlbstate[NR_CPUS];
-
-#endif /* CONFIG_SMP */
-
-static inline void flush_tlb_pgtables(struct mm_struct *mm,
- unsigned long start, unsigned long end)
-{
- /* i386 does not keep any page table caches in TLB */
- XENO_flush_page_update_queue();
-}
-
-#endif /* _I386_PGALLOC_H */
+++ /dev/null
-#ifndef _I386_PGTABLE_2LEVEL_H
-#define _I386_PGTABLE_2LEVEL_H
-
-/*
- * traditional i386 two-level paging structure:
- */
-
-#define PGDIR_SHIFT 22
-#define PTRS_PER_PGD 1024
-
-/*
- * the i386 is two-level, so we don't really have any
- * PMD directory physically.
- */
-#define PMD_SHIFT 22
-#define PTRS_PER_PMD 1
-
-#define PTRS_PER_PTE 1024
-
-#define pte_ERROR(e) \
- printk("%s:%d: bad pte %08lx.\n", __FILE__, __LINE__, (e).pte_low)
-#define pmd_ERROR(e) \
- printk("%s:%d: bad pmd %08lx.\n", __FILE__, __LINE__, pmd_val(e))
-#define pgd_ERROR(e) \
- printk("%s:%d: bad pgd %08lx.\n", __FILE__, __LINE__, pgd_val(e))
-
-/*
- * The "pgd_xxx()" functions here are trivial for a folded two-level
- * setup: the pgd is never bad, and a pmd always exists (as it's folded
- * into the pgd entry)
- */
-static inline int pgd_none(pgd_t pgd) { return 0; }
-static inline int pgd_bad(pgd_t pgd) { return 0; }
-static inline int pgd_present(pgd_t pgd) { return 1; }
-#define pgd_clear(xp) do { } while (0)
-
-#define set_pte(pteptr, pteval) queue_l1_entry_update(__pa(pteptr), (pteval).pte_low)
-#define set_pte_atomic(pteptr, pteval) queue_l1_entry_update(__pa(pteptr), (pteval).pte_low)
-#define set_pmd(pmdptr, pmdval) queue_l2_entry_update(__pa(pmdptr), (pmdval).pmd)
-#define set_pgd(pgdptr, pgdval) ((void)0)
-
-#define pgd_page(pgd) \
-((unsigned long) __va(pgd_val(pgd) & PAGE_MASK))
-
-static inline pmd_t * pmd_offset(pgd_t * dir, unsigned long address)
-{
- return (pmd_t *) dir;
-}
-
-/*
- * A note on implementation of this atomic 'get-and-clear' operation.
- * This is actually very simple because XenoLinux can only run on a single
- * processor. Therefore, we cannot race other processors setting the 'accessed'
- * or 'dirty' bits on a page-table entry.
- * Even if pages are shared between domains, that is not a problem because
- * each domain will have separate page tables, with their own versions of
- * accessed & dirty state.
- */
-static inline pte_t ptep_get_and_clear(pte_t *xp)
-{
- pte_t pte = *xp;
- queue_l1_entry_update(__pa(xp), 0);
- return pte;
-}
-
-#define pte_same(a, b) ((a).pte_low == (b).pte_low)
-#define pte_page(x) (mem_map+((unsigned long)((pte_val(x) >> PAGE_SHIFT))))
-#define pte_none(x) (!(x).pte_low)
-#define __mk_pte(page_nr,pgprot) __pte(((page_nr) << PAGE_SHIFT) | pgprot_val(pgprot))
-
-#endif /* _I386_PGTABLE_2LEVEL_H */
+++ /dev/null
-#ifndef _I386_PGTABLE_H
-#define _I386_PGTABLE_H
-
-#include <linux/config.h>
-
-#define HAVE_ARCH_UNMAPPED_AREA
-
-/*
- * The Linux memory management assumes a three-level page table setup. On
- * the i386, we use that, but "fold" the mid level into the top-level page
- * table, so that we physically have the same two-level page table as the
- * i386 mmu expects.
- *
- * This file contains the functions and defines necessary to modify and use
- * the i386 page table tree.
- */
-#ifndef __ASSEMBLY__
-#include <asm/processor.h>
-#include <asm/hypervisor.h>
-#include <linux/threads.h>
-#include <asm/fixmap.h>
-
-#ifndef _I386_BITOPS_H
-#include <asm/bitops.h>
-#endif
-
-#define swapper_pg_dir 0
-extern void paging_init(void);
-
-/* Caches aren't brain-dead on the intel. */
-#define flush_cache_all() do { } while (0)
-#define flush_cache_mm(mm) do { } while (0)
-#define flush_cache_range(mm, start, end) do { } while (0)
-#define flush_cache_page(vma, vmaddr) do { } while (0)
-#define flush_page_to_ram(page) do { } while (0)
-#define flush_dcache_page(page) do { } while (0)
-#define flush_icache_range(start, end) do { } while (0)
-#define flush_icache_page(vma,pg) do { } while (0)
-#define flush_icache_user_range(vma,pg,adr,len) do { } while (0)
-
-extern unsigned long pgkern_mask;
-
-#define __flush_tlb() ({ queue_tlb_flush(); XENO_flush_page_update_queue(); })
-#define __flush_tlb_global() __flush_tlb()
-#define __flush_tlb_all() __flush_tlb_global()
-#define __flush_tlb_one(addr) ({ queue_invlpg(addr); XENO_flush_page_update_queue(); })
-#define __flush_tlb_single(addr) ({ queue_invlpg(addr); XENO_flush_page_update_queue(); })
-
-/*
- * ZERO_PAGE is a global shared page that is always zero: used
- * for zero-mapped memory areas etc..
- */
-extern unsigned long empty_zero_page[1024];
-#define ZERO_PAGE(vaddr) (virt_to_page(empty_zero_page))
-
-#endif /* !__ASSEMBLY__ */
-
-/*
- * The Linux x86 paging architecture is 'compile-time dual-mode', it
- * implements both the traditional 2-level x86 page tables and the
- * newer 3-level PAE-mode page tables.
- */
-#ifndef __ASSEMBLY__
-#if CONFIG_X86_PAE
-# include <asm/pgtable-3level.h>
-
-/*
- * Need to initialise the X86 PAE caches
- */
-extern void pgtable_cache_init(void);
-
-#else
-# include <asm/pgtable-2level.h>
-
-/*
- * No page table caches to initialise
- */
-#define pgtable_cache_init() do { } while (0)
-
-#endif
-#endif
-
-#define PMD_SIZE (1UL << PMD_SHIFT)
-#define PMD_MASK (~(PMD_SIZE-1))
-#define PGDIR_SIZE (1UL << PGDIR_SHIFT)
-#define PGDIR_MASK (~(PGDIR_SIZE-1))
-
-#define USER_PTRS_PER_PGD (TASK_SIZE/PGDIR_SIZE)
-#define FIRST_USER_PGD_NR 0
-
-#define USER_PGD_PTRS (PAGE_OFFSET >> PGDIR_SHIFT)
-#define KERNEL_PGD_PTRS (PTRS_PER_PGD-USER_PGD_PTRS)
-
-#define TWOLEVEL_PGDIR_SHIFT 22
-#define BOOT_USER_PGD_PTRS (__PAGE_OFFSET >> TWOLEVEL_PGDIR_SHIFT)
-#define BOOT_KERNEL_PGD_PTRS (1024-BOOT_USER_PGD_PTRS)
-
-
-#ifndef __ASSEMBLY__
-/* 4MB is just a nice "safety zone". Also, we align to a fresh pde. */
-#define VMALLOC_OFFSET (4*1024*1024)
-extern void * high_memory;
-#define VMALLOC_START (((unsigned long) high_memory + 2*VMALLOC_OFFSET-1) & \
- ~(VMALLOC_OFFSET-1))
-#define VMALLOC_VMADDR(x) ((unsigned long)(x))
-#define VMALLOC_END (FIXADDR_START - 2*PAGE_SIZE)
-
-#define _PAGE_BIT_PRESENT 0
-#define _PAGE_BIT_RW 1
-#define _PAGE_BIT_USER 2
-#define _PAGE_BIT_PWT 3
-#define _PAGE_BIT_PCD 4
-#define _PAGE_BIT_ACCESSED 5
-#define _PAGE_BIT_DIRTY 6
-#define _PAGE_BIT_PSE 7 /* 4 MB (or 2MB) page, Pentium+, if present.. */
-#define _PAGE_BIT_GLOBAL 8 /* Global TLB entry PPro+ */
-
-#define _PAGE_PRESENT 0x001
-#define _PAGE_RW 0x002
-#define _PAGE_USER 0x004
-#define _PAGE_PWT 0x008
-#define _PAGE_PCD 0x010
-#define _PAGE_ACCESSED 0x020
-#define _PAGE_DIRTY 0x040
-#define _PAGE_PSE 0x080 /* 4 MB (or 2MB) page, Pentium+, if present.. */
-#define _PAGE_GLOBAL 0x100 /* Global TLB entry PPro+ */
-
-#define _PAGE_PROTNONE 0x080 /* If not present */
-
-#define _PAGE_TABLE (_PAGE_PRESENT | _PAGE_RW | _PAGE_USER | _PAGE_ACCESSED | _PAGE_DIRTY)
-#define _KERNPG_TABLE (_PAGE_PRESENT | _PAGE_RW | _PAGE_ACCESSED | _PAGE_DIRTY)
-#define _PAGE_CHG_MASK (PTE_MASK | _PAGE_ACCESSED | _PAGE_DIRTY)
-
-#define PAGE_NONE __pgprot(_PAGE_PROTNONE | _PAGE_ACCESSED)
-#define PAGE_SHARED __pgprot(_PAGE_PRESENT | _PAGE_RW | _PAGE_USER | _PAGE_ACCESSED)
-#define PAGE_COPY __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_ACCESSED)
-#define PAGE_READONLY __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_ACCESSED)
-
-#define __PAGE_KERNEL \
- (_PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY | _PAGE_ACCESSED)
-#define __PAGE_KERNEL_NOCACHE \
- (_PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY | _PAGE_PCD | _PAGE_ACCESSED)
-#define __PAGE_KERNEL_RO \
- (_PAGE_PRESENT | _PAGE_DIRTY | _PAGE_ACCESSED)
-
-#if 0
-#define MAKE_GLOBAL(x) __pgprot((x) | _PAGE_GLOBAL)
-#else
-#define MAKE_GLOBAL(x) __pgprot(x)
-#endif
-
-#define PAGE_KERNEL MAKE_GLOBAL(__PAGE_KERNEL)
-#define PAGE_KERNEL_RO MAKE_GLOBAL(__PAGE_KERNEL_RO)
-#define PAGE_KERNEL_NOCACHE MAKE_GLOBAL(__PAGE_KERNEL_NOCACHE)
-
-/*
- * The i386 can't do page protection for execute, and considers that
- * the same are read. Also, write permissions imply read permissions.
- * This is the closest we can get..
- */
-#define __P000 PAGE_NONE
-#define __P001 PAGE_READONLY
-#define __P010 PAGE_COPY
-#define __P011 PAGE_COPY
-#define __P100 PAGE_READONLY
-#define __P101 PAGE_READONLY
-#define __P110 PAGE_COPY
-#define __P111 PAGE_COPY
-
-#define __S000 PAGE_NONE
-#define __S001 PAGE_READONLY
-#define __S010 PAGE_SHARED
-#define __S011 PAGE_SHARED
-#define __S100 PAGE_READONLY
-#define __S101 PAGE_READONLY
-#define __S110 PAGE_SHARED
-#define __S111 PAGE_SHARED
-
-#define pte_present(x) ((x).pte_low & (_PAGE_PRESENT | _PAGE_PROTNONE))
-#define pte_clear(xp) queue_l1_entry_update(__pa(xp), 0)
-
-#define pmd_none(x) (!(x).pmd)
-#define pmd_present(x) ((x).pmd & _PAGE_PRESENT)
-#define pmd_clear(xp) do { set_pmd(xp, __pmd(0)); } while (0)
-#define pmd_bad(x) (((x).pmd & (~PAGE_MASK & ~_PAGE_USER)) != _KERNPG_TABLE)
-
-
-#define pages_to_mb(x) ((x) >> (20-PAGE_SHIFT))
-
-/*
- * The following only work if pte_present() is true.
- * Undefined behaviour if not..
- */
-static inline int pte_read(pte_t pte) { return (pte).pte_low & _PAGE_USER; }
-static inline int pte_exec(pte_t pte) { return (pte).pte_low & _PAGE_USER; }
-static inline int pte_dirty(pte_t pte) { return (pte).pte_low & _PAGE_DIRTY; }
-static inline int pte_young(pte_t pte) { return (pte).pte_low & _PAGE_ACCESSED; }
-static inline int pte_write(pte_t pte) { return (pte).pte_low & _PAGE_RW; }
-
-static inline pte_t pte_rdprotect(pte_t pte) { (pte).pte_low &= ~_PAGE_USER; return pte; }
-static inline pte_t pte_exprotect(pte_t pte) { (pte).pte_low &= ~_PAGE_USER; return pte; }
-static inline pte_t pte_mkclean(pte_t pte) { (pte).pte_low &= ~_PAGE_DIRTY; return pte; }
-static inline pte_t pte_mkold(pte_t pte) { (pte).pte_low &= ~_PAGE_ACCESSED; return pte; }
-static inline pte_t pte_wrprotect(pte_t pte) { (pte).pte_low &= ~_PAGE_RW; return pte; }
-static inline pte_t pte_mkread(pte_t pte) { (pte).pte_low |= _PAGE_USER; return pte; }
-static inline pte_t pte_mkexec(pte_t pte) { (pte).pte_low |= _PAGE_USER; return pte; }
-static inline pte_t pte_mkdirty(pte_t pte) { (pte).pte_low |= _PAGE_DIRTY; return pte; }
-static inline pte_t pte_mkyoung(pte_t pte) { (pte).pte_low |= _PAGE_ACCESSED; return pte; }
-static inline pte_t pte_mkwrite(pte_t pte) { (pte).pte_low |= _PAGE_RW; return pte; }
-
-static inline int ptep_test_and_clear_dirty(pte_t *ptep)
-{
- unsigned long pteval = *(unsigned long *)ptep;
- int ret = pteval & _PAGE_DIRTY;
- if ( ret ) queue_l1_entry_update(__pa(ptep), pteval & ~_PAGE_DIRTY);
- return ret;
-}
-static inline int ptep_test_and_clear_young(pte_t *ptep)
-{
- unsigned long pteval = *(unsigned long *)ptep;
- int ret = pteval & _PAGE_ACCESSED;
- if ( ret ) queue_l1_entry_update(__pa(ptep), pteval & ~_PAGE_ACCESSED);
- return ret;
-}
-static inline void ptep_set_wrprotect(pte_t *ptep)
-{
- unsigned long pteval = *(unsigned long *)ptep;
- if ( (pteval & _PAGE_RW) )
- queue_l1_entry_update(__pa(ptep), pteval & ~_PAGE_RW);
-}
-static inline void ptep_mkdirty(pte_t *ptep)
-{
- unsigned long pteval = *(unsigned long *)ptep;
- if ( !(pteval & _PAGE_DIRTY) )
- queue_l1_entry_update(__pa(ptep), pteval | _PAGE_DIRTY);
-}
-
-/*
- * Conversion functions: convert a page and protection to a page entry,
- * and a page entry and page directory to the page they refer to.
- */
-
-#define mk_pte(page, pgprot) __mk_pte((page) - mem_map, (pgprot))
-
-/* This takes a physical page address that is used by the remapping functions */
-#define mk_pte_phys(physpage, pgprot) __mk_pte((physpage) >> PAGE_SHIFT, pgprot)
-
-static inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
-{
- pte.pte_low &= _PAGE_CHG_MASK;
- pte.pte_low |= pgprot_val(newprot);
- return pte;
-}
-
-#define page_pte(page) page_pte_prot(page, __pgprot(0))
-
-#define pmd_page(pmd) \
-((unsigned long) __va(pmd_val(pmd) & PAGE_MASK))
-
-/* to find an entry in a page-table-directory. */
-#define pgd_index(address) ((address >> PGDIR_SHIFT) & (PTRS_PER_PGD-1))
-
-#define __pgd_offset(address) pgd_index(address)
-
-#define pgd_offset(mm, address) ((mm)->pgd+pgd_index(address))
-
-/* to find an entry in a kernel page-table-directory */
-#define pgd_offset_k(address) pgd_offset(&init_mm, address)
-
-#define __pmd_offset(address) \
- (((address) >> PMD_SHIFT) & (PTRS_PER_PMD-1))
-
-/* Find an entry in the third-level page table.. */
-#define __pte_offset(address) \
- ((address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1))
-#define pte_offset(dir, address) ((pte_t *) pmd_page(*(dir)) + \
- __pte_offset(address))
-
-/*
- * The i386 doesn't have any external MMU info: the kernel page
- * tables contain all the necessary information.
- */
-#define update_mmu_cache(vma,address,pte) do { } while (0)
-
-/* Encode and de-code a swap entry */
-#define SWP_TYPE(x) (((x).val >> 1) & 0x3f)
-#define SWP_OFFSET(x) ((x).val >> 8)
-#define SWP_ENTRY(type, offset) ((swp_entry_t) { ((type) << 1) | ((offset) << 8) })
-#define pte_to_swp_entry(pte) ((swp_entry_t) { (pte).pte_low })
-#define swp_entry_to_pte(x) ((pte_t) { (x).val })
-
-struct page;
-int change_page_attr(struct page *, int, pgprot_t prot);
-
-static inline void __make_page_readonly(void *va)
-{
- pgd_t *pgd = pgd_offset_k((unsigned long)va);
- pmd_t *pmd = pmd_offset(pgd, (unsigned long)va);
- pte_t *pte = pte_offset(pmd, (unsigned long)va);
- queue_l1_entry_update(__pa(pte), (*(unsigned long *)pte)&~_PAGE_RW);
-}
-
-static inline void __make_page_writeable(void *va)
-{
- pgd_t *pgd = pgd_offset_k((unsigned long)va);
- pmd_t *pmd = pmd_offset(pgd, (unsigned long)va);
- pte_t *pte = pte_offset(pmd, (unsigned long)va);
- queue_l1_entry_update(__pa(pte), (*(unsigned long *)pte)|_PAGE_RW);
-}
-
-static inline void make_page_readonly(void *va)
-{
- pgd_t *pgd = pgd_offset_k((unsigned long)va);
- pmd_t *pmd = pmd_offset(pgd, (unsigned long)va);
- pte_t *pte = pte_offset(pmd, (unsigned long)va);
- queue_l1_entry_update(__pa(pte), (*(unsigned long *)pte)&~_PAGE_RW);
- if ( (unsigned long)va >= VMALLOC_START )
- __make_page_readonly(machine_to_virt(
- *(unsigned long *)pte&PAGE_MASK));
-}
-
-static inline void make_page_writeable(void *va)
-{
- pgd_t *pgd = pgd_offset_k((unsigned long)va);
- pmd_t *pmd = pmd_offset(pgd, (unsigned long)va);
- pte_t *pte = pte_offset(pmd, (unsigned long)va);
- queue_l1_entry_update(__pa(pte), (*(unsigned long *)pte)|_PAGE_RW);
- if ( (unsigned long)va >= VMALLOC_START )
- __make_page_writeable(machine_to_virt(
- *(unsigned long *)pte&PAGE_MASK));
-}
-
-static inline void make_pages_readonly(void *va, unsigned int nr)
-{
- while ( nr-- != 0 )
- {
- make_page_readonly(va);
- va = (void *)((unsigned long)va + PAGE_SIZE);
- }
-}
-
-static inline void make_pages_writeable(void *va, unsigned int nr)
-{
- while ( nr-- != 0 )
- {
- make_page_writeable(va);
- va = (void *)((unsigned long)va + PAGE_SIZE);
- }
-}
-
-static inline unsigned long arbitrary_virt_to_phys(void *va)
-{
- pgd_t *pgd = pgd_offset_k((unsigned long)va);
- pmd_t *pmd = pmd_offset(pgd, (unsigned long)va);
- pte_t *pte = pte_offset(pmd, (unsigned long)va);
- unsigned long pa = (*(unsigned long *)pte) & PAGE_MASK;
- return pa | ((unsigned long)va & (PAGE_SIZE-1));
-}
-
-#endif /* !__ASSEMBLY__ */
-
-/* Needs to be defined here and not in linux/mm.h, as it is arch dependent */
-#define PageSkip(page) (0)
-#define kern_addr_valid(addr) (1)
-
-#define io_remap_page_range remap_page_range
-
-#endif /* _I386_PGTABLE_H */
+++ /dev/null
-/*
- * include/asm-i386/processor.h
- *
- * Copyright (C) 1994 Linus Torvalds
- */
-
-#ifndef __ASM_I386_PROCESSOR_H
-#define __ASM_I386_PROCESSOR_H
-
-#include <asm/math_emu.h>
-#include <asm/segment.h>
-#include <asm/page.h>
-#include <asm/types.h>
-#include <asm/sigcontext.h>
-#include <asm/cpufeature.h>
-#include <linux/cache.h>
-#include <linux/config.h>
-#include <linux/threads.h>
-
-/*
- * Default implementation of macro that returns current
- * instruction pointer ("program counter").
- */
-#define current_text_addr() ({ void *pc; __asm__("movl $1f,%0\n1:":"=g" (pc)); pc; })
-
-/*
- * CPU type and hardware bug flags. Kept separately for each CPU.
- * Members of this structure are referenced in head.S, so think twice
- * before touching them. [mj]
- */
-
-struct cpuinfo_x86 {
- __u8 x86; /* CPU family */
- __u8 x86_vendor; /* CPU vendor */
- __u8 x86_model;
- __u8 x86_mask;
- char wp_works_ok; /* It doesn't on 386's */
- char hlt_works_ok; /* Problems on some 486Dx4's and old 386's */
- char hard_math;
- char rfu;
- int cpuid_level; /* Maximum supported CPUID level, -1=no CPUID */
- __u32 x86_capability[NCAPINTS];
- char x86_vendor_id[16];
- char x86_model_id[64];
- int x86_cache_size; /* in KB - valid for CPUS which support this
- call */
- int fdiv_bug;
- int f00f_bug;
- int coma_bug;
- unsigned long loops_per_jiffy;
- unsigned long *pgd_quick;
- unsigned long *pmd_quick;
- unsigned long *pte_quick;
- unsigned long pgtable_cache_sz;
-} __attribute__((__aligned__(SMP_CACHE_BYTES)));
-
-#define X86_VENDOR_INTEL 0
-#define X86_VENDOR_CYRIX 1
-#define X86_VENDOR_AMD 2
-#define X86_VENDOR_UMC 3
-#define X86_VENDOR_NEXGEN 4
-#define X86_VENDOR_CENTAUR 5
-#define X86_VENDOR_RISE 6
-#define X86_VENDOR_TRANSMETA 7
-#define X86_VENDOR_NSC 8
-#define X86_VENDOR_UNKNOWN 0xff
-
-/*
- * capabilities of CPUs
- */
-
-extern struct cpuinfo_x86 boot_cpu_data;
-extern struct tss_struct init_tss[NR_CPUS];
-
-#ifdef CONFIG_SMP
-extern struct cpuinfo_x86 cpu_data[];
-#define current_cpu_data cpu_data[smp_processor_id()]
-#else
-#define cpu_data (&boot_cpu_data)
-#define current_cpu_data boot_cpu_data
-#endif
-
-#define cpu_has_pge (test_bit(X86_FEATURE_PGE, boot_cpu_data.x86_capability))
-#define cpu_has_pse (test_bit(X86_FEATURE_PSE, boot_cpu_data.x86_capability))
-#define cpu_has_pae (test_bit(X86_FEATURE_PAE, boot_cpu_data.x86_capability))
-#define cpu_has_tsc (test_bit(X86_FEATURE_TSC, boot_cpu_data.x86_capability))
-#define cpu_has_de (test_bit(X86_FEATURE_DE, boot_cpu_data.x86_capability))
-#define cpu_has_vme (test_bit(X86_FEATURE_VME, boot_cpu_data.x86_capability))
-#define cpu_has_fxsr (test_bit(X86_FEATURE_FXSR, boot_cpu_data.x86_capability))
-#define cpu_has_xmm (test_bit(X86_FEATURE_XMM, boot_cpu_data.x86_capability))
-#define cpu_has_fpu (test_bit(X86_FEATURE_FPU, boot_cpu_data.x86_capability))
-#define cpu_has_apic (test_bit(X86_FEATURE_APIC, boot_cpu_data.x86_capability))
-
-extern char ignore_irq13;
-
-extern void identify_cpu(struct cpuinfo_x86 *);
-extern void print_cpu_info(struct cpuinfo_x86 *);
-
-/*
- * EFLAGS bits
- */
-#define X86_EFLAGS_CF 0x00000001 /* Carry Flag */
-#define X86_EFLAGS_PF 0x00000004 /* Parity Flag */
-#define X86_EFLAGS_AF 0x00000010 /* Auxillary carry Flag */
-#define X86_EFLAGS_ZF 0x00000040 /* Zero Flag */
-#define X86_EFLAGS_SF 0x00000080 /* Sign Flag */
-#define X86_EFLAGS_TF 0x00000100 /* Trap Flag */
-#define X86_EFLAGS_IF 0x00000200 /* Interrupt Flag */
-#define X86_EFLAGS_DF 0x00000400 /* Direction Flag */
-#define X86_EFLAGS_OF 0x00000800 /* Overflow Flag */
-#define X86_EFLAGS_IOPL 0x00003000 /* IOPL mask */
-#define X86_EFLAGS_NT 0x00004000 /* Nested Task */
-#define X86_EFLAGS_RF 0x00010000 /* Resume Flag */
-#define X86_EFLAGS_VM 0x00020000 /* Virtual Mode */
-#define X86_EFLAGS_AC 0x00040000 /* Alignment Check */
-#define X86_EFLAGS_VIF 0x00080000 /* Virtual Interrupt Flag */
-#define X86_EFLAGS_VIP 0x00100000 /* Virtual Interrupt Pending */
-#define X86_EFLAGS_ID 0x00200000 /* CPUID detection flag */
-
-/*
- * Generic CPUID function
- */
-static inline void cpuid(int op, int *eax, int *ebx, int *ecx, int *edx)
-{
- __asm__("cpuid"
- : "=a" (*eax),
- "=b" (*ebx),
- "=c" (*ecx),
- "=d" (*edx)
- : "0" (op));
-}
-
-/*
- * CPUID functions returning a single datum
- */
-static inline unsigned int cpuid_eax(unsigned int op)
-{
- unsigned int eax;
-
- __asm__("cpuid"
- : "=a" (eax)
- : "0" (op)
- : "bx", "cx", "dx");
- return eax;
-}
-static inline unsigned int cpuid_ebx(unsigned int op)
-{
- unsigned int eax, ebx;
-
- __asm__("cpuid"
- : "=a" (eax), "=b" (ebx)
- : "0" (op)
- : "cx", "dx" );
- return ebx;
-}
-static inline unsigned int cpuid_ecx(unsigned int op)
-{
- unsigned int eax, ecx;
-
- __asm__("cpuid"
- : "=a" (eax), "=c" (ecx)
- : "0" (op)
- : "bx", "dx" );
- return ecx;
-}
-static inline unsigned int cpuid_edx(unsigned int op)
-{
- unsigned int eax, edx;
-
- __asm__("cpuid"
- : "=a" (eax), "=d" (edx)
- : "0" (op)
- : "bx", "cx");
- return edx;
-}
-
-/*
- * Intel CPU features in CR4
- */
-#define X86_CR4_VME 0x0001 /* enable vm86 extensions */
-#define X86_CR4_PVI 0x0002 /* virtual interrupts flag enable */
-#define X86_CR4_TSD 0x0004 /* disable time stamp at ipl 3 */
-#define X86_CR4_DE 0x0008 /* enable debugging extensions */
-#define X86_CR4_PSE 0x0010 /* enable page size extensions */
-#define X86_CR4_PAE 0x0020 /* enable physical address extensions */
-#define X86_CR4_MCE 0x0040 /* Machine check enable */
-#define X86_CR4_PGE 0x0080 /* enable global pages */
-#define X86_CR4_PCE 0x0100 /* enable performance counters at ipl 3 */
-#define X86_CR4_OSFXSR 0x0200 /* enable fast FPU save and restore */
-#define X86_CR4_OSXMMEXCPT 0x0400 /* enable unmasked SSE exceptions */
-
-#define load_cr3(pgdir) \
- asm volatile("movl %0,%%cr3": :"r" (__pa(pgdir)));
-
-extern unsigned long mmu_cr4_features;
-
-#include <asm/hypervisor.h>
-
-static inline void set_in_cr4 (unsigned long mask)
-{
- HYPERVISOR_console_write("No set_in_cr4", 13);
-}
-
-static inline void clear_in_cr4 (unsigned long mask)
-{
- HYPERVISOR_console_write("No clear_in_cr4", 15);
-}
-
-/*
- * Cyrix CPU configuration register indexes
- */
-#define CX86_CCR0 0xc0
-#define CX86_CCR1 0xc1
-#define CX86_CCR2 0xc2
-#define CX86_CCR3 0xc3
-#define CX86_CCR4 0xe8
-#define CX86_CCR5 0xe9
-#define CX86_CCR6 0xea
-#define CX86_CCR7 0xeb
-#define CX86_DIR0 0xfe
-#define CX86_DIR1 0xff
-#define CX86_ARR_BASE 0xc4
-#define CX86_RCR_BASE 0xdc
-
-/*
- * Cyrix CPU indexed register access macros
- */
-
-#define getCx86(reg) ({ outb((reg), 0x22); inb(0x23); })
-
-#define setCx86(reg, data) do { \
- outb((reg), 0x22); \
- outb((data), 0x23); \
-} while (0)
-
-/*
- * Bus types (default is ISA, but people can check others with these..)
- */
-#ifdef CONFIG_EISA
-extern int EISA_bus;
-#else
-#define EISA_bus (0)
-#endif
-extern int MCA_bus;
-
-/* from system description table in BIOS. Mostly for MCA use, but
-others may find it useful. */
-extern unsigned int machine_id;
-extern unsigned int machine_submodel_id;
-extern unsigned int BIOS_revision;
-extern unsigned int mca_pentium_flag;
-
-/*
- * User space process size: 3GB (default).
- */
-#define TASK_SIZE (PAGE_OFFSET)
-
-/* This decides where the kernel will search for a free chunk of vm
- * space during mmap's.
- */
-#define TASK_UNMAPPED_BASE (TASK_SIZE / 3)
-
-/*
- * Size of io_bitmap in longwords: 32 is ports 0-0x3ff.
- */
-#define IO_BITMAP_SIZE 32
-#define IO_BITMAP_OFFSET offsetof(struct tss_struct,io_bitmap)
-#define INVALID_IO_BITMAP_OFFSET 0x8000
-
-struct i387_fsave_struct {
- long cwd;
- long swd;
- long twd;
- long fip;
- long fcs;
- long foo;
- long fos;
- long st_space[20]; /* 8*10 bytes for each FP-reg = 80 bytes */
- long status; /* software status information */
-};
-
-struct i387_fxsave_struct {
- unsigned short cwd;
- unsigned short swd;
- unsigned short twd;
- unsigned short fop;
- long fip;
- long fcs;
- long foo;
- long fos;
- long mxcsr;
- long reserved;
- long st_space[32]; /* 8*16 bytes for each FP-reg = 128 bytes */
- long xmm_space[32]; /* 8*16 bytes for each XMM-reg = 128 bytes */
- long padding[56];
-} __attribute__ ((aligned (16)));
-
-struct i387_soft_struct {
- long cwd;
- long swd;
- long twd;
- long fip;
- long fcs;
- long foo;
- long fos;
- long st_space[20]; /* 8*10 bytes for each FP-reg = 80 bytes */
- unsigned char ftop, changed, lookahead, no_update, rm, alimit;
- struct info *info;
- unsigned long entry_eip;
-};
-
-union i387_union {
- struct i387_fsave_struct fsave;
- struct i387_fxsave_struct fxsave;
- struct i387_soft_struct soft;
-};
-
-typedef struct {
- unsigned long seg;
-} mm_segment_t;
-
-struct tss_struct {
- unsigned short back_link,__blh;
- unsigned long esp0;
- unsigned short ss0,__ss0h;
- unsigned long esp1;
- unsigned short ss1,__ss1h;
- unsigned long esp2;
- unsigned short ss2,__ss2h;
- unsigned long __cr3;
- unsigned long eip;
- unsigned long eflags;
- unsigned long eax,ecx,edx,ebx;
- unsigned long esp;
- unsigned long ebp;
- unsigned long esi;
- unsigned long edi;
- unsigned short es, __esh;
- unsigned short cs, __csh;
- unsigned short ss, __ssh;
- unsigned short ds, __dsh;
- unsigned short fs, __fsh;
- unsigned short gs, __gsh;
- unsigned short ldt, __ldth;
- unsigned short trace, bitmap;
- unsigned long io_bitmap[IO_BITMAP_SIZE+1];
- /*
- * pads the TSS to be cacheline-aligned (size is 0x100)
- */
- unsigned long __cacheline_filler[5];
-};
-
-struct thread_struct {
- unsigned long esp0;
- unsigned long eip;
- unsigned long esp;
- unsigned long fs;
- unsigned long gs;
- unsigned int io_pl, hypercall_pl;
-/* Hardware debugging registers */
- unsigned long debugreg[8]; /* %%db0-7 debug registers */
-/* fault info */
- unsigned long cr2, trap_no, error_code;
-/* floating point info */
- union i387_union i387;
-/* virtual 86 mode info */
- struct vm86_struct * vm86_info;
- unsigned long screen_bitmap;
- unsigned long v86flags, v86mask, saved_esp0;
-};
-
-#define INIT_THREAD { sizeof(init_stack) + (long) &init_stack, \
- 0, 0, 0, 0, 0, 0, {0}, 0, 0, 0, {0}, 0, 0, 0, 0, 0 }
-
-#define INIT_TSS { \
- 0,0, /* back_link, __blh */ \
- sizeof(init_stack) + (long) &init_stack, /* esp0 */ \
- __KERNEL_DS, 0, /* ss0 */ \
- 0,0,0,0,0,0, /* stack1, stack2 */ \
- 0, /* cr3 */ \
- 0,0, /* eip,eflags */ \
- 0,0,0,0, /* eax,ecx,edx,ebx */ \
- 0,0,0,0, /* esp,ebp,esi,edi */ \
- 0,0,0,0,0,0, /* es,cs,ss */ \
- 0,0,0,0,0,0, /* ds,fs,gs */ \
- 0,0, /* ldt */ \
- 0, INVALID_IO_BITMAP_OFFSET, /* tace, bitmap */ \
- {~0, } /* ioperm */ \
-}
-
-#define start_thread(regs, new_eip, new_esp) do { \
- __asm__("movl %0,%%fs ; movl %0,%%gs": :"r" (0)); \
- set_fs(USER_DS); \
- regs->xds = __USER_DS; \
- regs->xes = __USER_DS; \
- regs->xss = __USER_DS; \
- regs->xcs = __USER_CS; \
- regs->eip = new_eip; \
- regs->esp = new_esp; \
-} while (0)
-
-/* Forward declaration, a strange C thing */
-struct task_struct;
-struct mm_struct;
-
-/* Free all resources held by a thread. */
-extern void release_thread(struct task_struct *);
-/*
- * create a kernel thread without removing it from tasklists
- */
-extern int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags);
-
-/* Copy and release all segment info associated with a VM */
-extern void copy_segments(struct task_struct *p, struct mm_struct * mm);
-extern void release_segments(struct mm_struct * mm);
-
-/*
- * Return saved PC of a blocked thread.
- */
-static inline unsigned long thread_saved_pc(struct thread_struct *t)
-{
- return ((unsigned long *)t->esp)[3];
-}
-
-unsigned long get_wchan(struct task_struct *p);
-#define KSTK_EIP(tsk) (((unsigned long *)(4096+(unsigned long)(tsk)))[1019])
-#define KSTK_ESP(tsk) (((unsigned long *)(4096+(unsigned long)(tsk)))[1022])
-
-#define THREAD_SIZE (2*PAGE_SIZE)
-#define alloc_task_struct() ((struct task_struct *) __get_free_pages(GFP_KERNEL,1))
-#define free_task_struct(p) free_pages((unsigned long) (p), 1)
-#define get_task_struct(tsk) atomic_inc(&virt_to_page(tsk)->count)
-
-#define init_task (init_task_union.task)
-#define init_stack (init_task_union.stack)
-
-struct microcode {
- unsigned int hdrver;
- unsigned int rev;
- unsigned int date;
- unsigned int sig;
- unsigned int cksum;
- unsigned int ldrver;
- unsigned int pf;
- unsigned int reserved[5];
- unsigned int bits[500];
-};
-
-/* '6' because it used to be for P6 only (but now covers Pentium 4 as well) */
-#define MICROCODE_IOCFREE _IO('6',0)
-
-/* REP NOP (PAUSE) is a good thing to insert into busy-wait loops. */
-static inline void rep_nop(void)
-{
- __asm__ __volatile__("rep;nop");
-}
-
-#define cpu_relax() rep_nop()
-
-/* Prefetch instructions for Pentium III and AMD Athlon */
-#ifdef CONFIG_MPENTIUMIII
-
-#define ARCH_HAS_PREFETCH
-extern inline void prefetch(const void *x)
-{
- __asm__ __volatile__ ("prefetchnta (%0)" : : "r"(x));
-}
-
-#elif CONFIG_X86_USE_3DNOW
-
-#define ARCH_HAS_PREFETCH
-#define ARCH_HAS_PREFETCHW
-#define ARCH_HAS_SPINLOCK_PREFETCH
-
-extern inline void prefetch(const void *x)
-{
- __asm__ __volatile__ ("prefetch (%0)" : : "r"(x));
-}
-
-extern inline void prefetchw(const void *x)
-{
- __asm__ __volatile__ ("prefetchw (%0)" : : "r"(x));
-}
-#define spin_lock_prefetch(x) prefetchw(x)
-
-#endif
-
-#define TF_MASK 0x100
-
-#endif /* __ASM_I386_PROCESSOR_H */
+++ /dev/null
-#ifndef _I386_PTRACE_H
-#define _I386_PTRACE_H
-
-#define EBX 0
-#define ECX 1
-#define EDX 2
-#define ESI 3
-#define EDI 4
-#define EBP 5
-#define EAX 6
-#define DS 7
-#define ES 8
-#define FS 9
-#define GS 10
-#define ORIG_EAX 11
-#define EIP 12
-#define CS 13
-#define EFL 14
-#define UESP 15
-#define SS 16
-#define FRAME_SIZE 17
-
-/* this struct defines the way the registers are stored on the
- stack during a system call. */
-
-struct pt_regs {
- long ebx;
- long ecx;
- long edx;
- long esi;
- long edi;
- long ebp;
- long eax;
- int xds;
- int xes;
- long orig_eax;
- long eip;
- int xcs;
- long eflags;
- long esp;
- int xss;
-};
-
-/* Arbitrarily choose the same ptrace numbers as used by the Sparc code. */
-#define PTRACE_GETREGS 12
-#define PTRACE_SETREGS 13
-#define PTRACE_GETFPREGS 14
-#define PTRACE_SETFPREGS 15
-#define PTRACE_GETFPXREGS 18
-#define PTRACE_SETFPXREGS 19
-
-#define PTRACE_SETOPTIONS 21
-
-/* options set using PTRACE_SETOPTIONS */
-#define PTRACE_O_TRACESYSGOOD 0x00000001
-
-#ifdef __KERNEL__
-#define user_mode(regs) ((regs) && (2 & (regs)->xcs))
-#define instruction_pointer(regs) ((regs) ? (regs)->eip : NULL)
-extern void show_regs(struct pt_regs *);
-#endif
-
-#endif
+++ /dev/null
-#ifndef _ASM_SEGMENT_H
-#define _ASM_SEGMENT_H
-
-#include <asm/hypervisor-ifs/hypervisor-if.h>
-
-#define __KERNEL_CS FLAT_RING1_CS
-#define __KERNEL_DS FLAT_RING1_DS
-
-#define __USER_CS FLAT_RING3_CS
-#define __USER_DS FLAT_RING3_DS
-
-#endif
+++ /dev/null
-#ifndef __ASM_SMP_H
-#define __ASM_SMP_H
-
-/*
- * We need the APIC definitions automatically as part of 'smp.h'
- */
-#ifndef __ASSEMBLY__
-#include <linux/config.h>
-#include <linux/threads.h>
-#include <linux/ptrace.h>
-#endif
-
-#ifdef CONFIG_X86_LOCAL_APIC
-#ifndef __ASSEMBLY__
-#include <asm/bitops.h>
-#include <asm/mpspec.h>
-#ifdef CONFIG_X86_IO_APIC
-#include <asm/io_apic.h>
-#endif
-#include <asm/apic.h>
-#endif
-#endif
-
-#ifdef CONFIG_SMP
-#ifndef __ASSEMBLY__
-
-/*
- * Private routines/data
- */
-
-extern void smp_alloc_memory(void);
-extern unsigned long phys_cpu_present_map;
-extern unsigned long cpu_online_map;
-extern volatile unsigned long smp_invalidate_needed;
-extern int pic_mode;
-extern int smp_num_siblings;
-extern int cpu_sibling_map[];
-
-extern void smp_flush_tlb(void);
-extern void smp_message_irq(int cpl, void *dev_id, struct pt_regs *regs);
-extern void smp_send_reschedule(int cpu);
-extern void smp_invalidate_rcv(void); /* Process an NMI */
-extern void (*mtrr_hook) (void);
-extern void zap_low_mappings (void);
-
-/*
- * On x86 all CPUs are mapped 1:1 to the APIC space.
- * This simplifies scheduling and IPI sending and
- * compresses data structures.
- */
-static inline int cpu_logical_map(int cpu)
-{
- return cpu;
-}
-static inline int cpu_number_map(int cpu)
-{
- return cpu;
-}
-
-/*
- * Some lowlevel functions might want to know about
- * the real APIC ID <-> CPU # mapping.
- */
-#define MAX_APICID 256
-extern volatile int cpu_to_physical_apicid[NR_CPUS];
-extern volatile int physical_apicid_to_cpu[MAX_APICID];
-extern volatile int cpu_to_logical_apicid[NR_CPUS];
-extern volatile int logical_apicid_to_cpu[MAX_APICID];
-
-/*
- * General functions that each host system must provide.
- */
-
-extern void smp_boot_cpus(void);
-extern void smp_store_cpu_info(int id); /* Store per CPU info (like the initial udelay numbers */
-
-/*
- * This function is needed by all SMP systems. It must _always_ be valid
- * from the initial startup. We map APIC_BASE very early in page_setup(),
- * so this is correct in the x86 case.
- */
-
-#define smp_processor_id() (current->processor)
-
-#endif /* !__ASSEMBLY__ */
-
-#define NO_PROC_ID 0xFF /* No processor magic marker */
-
-/*
- * This magic constant controls our willingness to transfer
- * a process across CPUs. Such a transfer incurs misses on the L1
- * cache, and on a P6 or P5 with multiple L2 caches L2 hits. My
- * gut feeling is this will vary by board in value. For a board
- * with separate L2 cache it probably depends also on the RSS, and
- * for a board with shared L2 cache it ought to decay fast as other
- * processes are run.
- */
-
-#define PROC_CHANGE_PENALTY 15 /* Schedule penalty */
-
-#endif
-#endif
+++ /dev/null
-#ifndef __ASM_SYSTEM_H
-#define __ASM_SYSTEM_H
-
-#include <linux/config.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <asm/segment.h>
-#include <asm/hypervisor.h>
-#include <linux/bitops.h> /* for LOCK_PREFIX */
-
-#ifdef __KERNEL__
-
-struct task_struct;
-extern void FASTCALL(__switch_to(struct task_struct *prev,
- struct task_struct *next));
-
-#define prepare_to_switch() \
-do { \
- struct thread_struct *__t = ¤t->thread; \
- __asm__ __volatile__ ( "movl %%fs,%0" : "=m" (*(int *)&__t->fs) ); \
- __asm__ __volatile__ ( "movl %%gs,%0" : "=m" (*(int *)&__t->gs) ); \
-} while (0)
-#define switch_to(prev,next,last) do { \
- asm volatile("pushl %%esi\n\t" \
- "pushl %%edi\n\t" \
- "pushl %%ebp\n\t" \
- "movl %%esp,%0\n\t" /* save ESP */ \
- "movl %3,%%esp\n\t" /* restore ESP */ \
- "movl $1f,%1\n\t" /* save EIP */ \
- "pushl %4\n\t" /* restore EIP */ \
- "jmp __switch_to\n" \
- "1:\t" \
- "popl %%ebp\n\t" \
- "popl %%edi\n\t" \
- "popl %%esi\n\t" \
- :"=m" (prev->thread.esp),"=m" (prev->thread.eip), \
- "=b" (last) \
- :"m" (next->thread.esp),"m" (next->thread.eip), \
- "a" (prev), "d" (next), \
- "b" (prev)); \
-} while (0)
-
-#define _set_base(addr,base) do { unsigned long __pr; \
-__asm__ __volatile__ ("movw %%dx,%1\n\t" \
- "rorl $16,%%edx\n\t" \
- "movb %%dl,%2\n\t" \
- "movb %%dh,%3" \
- :"=&d" (__pr) \
- :"m" (*((addr)+2)), \
- "m" (*((addr)+4)), \
- "m" (*((addr)+7)), \
- "0" (base) \
- ); } while(0)
-
-#define _set_limit(addr,limit) do { unsigned long __lr; \
-__asm__ __volatile__ ("movw %%dx,%1\n\t" \
- "rorl $16,%%edx\n\t" \
- "movb %2,%%dh\n\t" \
- "andb $0xf0,%%dh\n\t" \
- "orb %%dh,%%dl\n\t" \
- "movb %%dl,%2" \
- :"=&d" (__lr) \
- :"m" (*(addr)), \
- "m" (*((addr)+6)), \
- "0" (limit) \
- ); } while(0)
-
-#define set_base(ldt,base) _set_base( ((char *)&(ldt)) , (base) )
-#define set_limit(ldt,limit) _set_limit( ((char *)&(ldt)) , ((limit)-1)>>12 )
-
-static inline unsigned long _get_base(char * addr)
-{
- unsigned long __base;
- __asm__("movb %3,%%dh\n\t"
- "movb %2,%%dl\n\t"
- "shll $16,%%edx\n\t"
- "movw %1,%%dx"
- :"=&d" (__base)
- :"m" (*((addr)+2)),
- "m" (*((addr)+4)),
- "m" (*((addr)+7)));
- return __base;
-}
-
-#define get_base(ldt) _get_base( ((char *)&(ldt)) )
-
-/*
- * Load a segment. Fall back on loading the zero
- * segment if something goes wrong..
- */
-#define loadsegment(seg,value) \
- asm volatile("\n" \
- "1:\t" \
- "movl %0,%%" #seg "\n" \
- "2:\n" \
- ".section .fixup,\"ax\"\n" \
- "3:\t" \
- "pushl $0\n\t" \
- "popl %%" #seg "\n\t" \
- "jmp 2b\n" \
- ".previous\n" \
- ".section __ex_table,\"a\"\n\t" \
- ".align 4\n\t" \
- ".long 1b,3b\n" \
- ".previous" \
- : :"m" (*(unsigned int *)&(value)))
-
-#define clts() ((void)0)
-#define read_cr0() ({ \
- unsigned int __dummy; \
- __asm__( \
- "movl %%cr0,%0\n\t" \
- :"=r" (__dummy)); \
- __dummy; \
-})
-#define write_cr0(x) \
- __asm__("movl %0,%%cr0": :"r" (x));
-
-#define read_cr4() ({ \
- unsigned int __dummy; \
- __asm__( \
- "movl %%cr4,%0\n\t" \
- :"=r" (__dummy)); \
- __dummy; \
-})
-#define write_cr4(x) \
- __asm__("movl %0,%%cr4": :"r" (x));
-#define stts() (HYPERVISOR_fpu_taskswitch())
-
-#endif /* __KERNEL__ */
-
-#define wbinvd() \
- __asm__ __volatile__ ("wbinvd": : :"memory");
-
-static inline unsigned long get_limit(unsigned long segment)
-{
- unsigned long __limit;
- __asm__("lsll %1,%0"
- :"=r" (__limit):"r" (segment));
- return __limit+1;
-}
-
-#define nop() __asm__ __volatile__ ("nop")
-
-#define xchg(ptr,v) ((__typeof__(*(ptr)))__xchg((unsigned long)(v),(ptr),sizeof(*(ptr))))
-
-#define tas(ptr) (xchg((ptr),1))
-
-struct __xchg_dummy { unsigned long a[100]; };
-#define __xg(x) ((struct __xchg_dummy *)(x))
-
-
-/*
- * The semantics of XCHGCMP8B are a bit strange, this is why
- * there is a loop and the loading of %%eax and %%edx has to
- * be inside. This inlines well in most cases, the cached
- * cost is around ~38 cycles. (in the future we might want
- * to do an SIMD/3DNOW!/MMX/FPU 64-bit store here, but that
- * might have an implicit FPU-save as a cost, so it's not
- * clear which path to go.)
- *
- * chmxchg8b must be used with the lock prefix here to allow
- * the instruction to be executed atomically, see page 3-102
- * of the instruction set reference 24319102.pdf. We need
- * the reader side to see the coherent 64bit value.
- */
-static inline void __set_64bit (unsigned long long * ptr,
- unsigned int low, unsigned int high)
-{
- __asm__ __volatile__ (
- "\n1:\t"
- "movl (%0), %%eax\n\t"
- "movl 4(%0), %%edx\n\t"
- "lock cmpxchg8b (%0)\n\t"
- "jnz 1b"
- : /* no outputs */
- : "D"(ptr),
- "b"(low),
- "c"(high)
- : "ax","dx","memory");
-}
-
-static inline void __set_64bit_constant (unsigned long long *ptr,
- unsigned long long value)
-{
- __set_64bit(ptr,(unsigned int)(value), (unsigned int)((value)>>32ULL));
-}
-#define ll_low(x) *(((unsigned int*)&(x))+0)
-#define ll_high(x) *(((unsigned int*)&(x))+1)
-
-static inline void __set_64bit_var (unsigned long long *ptr,
- unsigned long long value)
-{
- __set_64bit(ptr,ll_low(value), ll_high(value));
-}
-
-#define set_64bit(ptr,value) \
-(__builtin_constant_p(value) ? \
- __set_64bit_constant(ptr, value) : \
- __set_64bit_var(ptr, value) )
-
-#define _set_64bit(ptr,value) \
-(__builtin_constant_p(value) ? \
- __set_64bit(ptr, (unsigned int)(value), (unsigned int)((value)>>32ULL) ) : \
- __set_64bit(ptr, ll_low(value), ll_high(value)) )
-
-/*
- * Note: no "lock" prefix even on SMP: xchg always implies lock anyway
- * Note 2: xchg has side effect, so that attribute volatile is necessary,
- * but generally the primitive is invalid, *ptr is output argument. --ANK
- */
-static inline unsigned long __xchg(unsigned long x, volatile void * ptr, int size)
-{
- switch (size) {
- case 1:
- __asm__ __volatile__("xchgb %b0,%1"
- :"=q" (x)
- :"m" (*__xg(ptr)), "0" (x)
- :"memory");
- break;
- case 2:
- __asm__ __volatile__("xchgw %w0,%1"
- :"=r" (x)
- :"m" (*__xg(ptr)), "0" (x)
- :"memory");
- break;
- case 4:
- __asm__ __volatile__("xchgl %0,%1"
- :"=r" (x)
- :"m" (*__xg(ptr)), "0" (x)
- :"memory");
- break;
- }
- return x;
-}
-
-/*
- * Atomic compare and exchange. Compare OLD with MEM, if identical,
- * store NEW in MEM. Return the initial value in MEM. Success is
- * indicated by comparing RETURN with OLD.
- */
-
-#ifdef CONFIG_X86_CMPXCHG
-#define __HAVE_ARCH_CMPXCHG 1
-
-static inline unsigned long __cmpxchg(volatile void *ptr, unsigned long old,
- unsigned long new, int size)
-{
- unsigned long prev;
- switch (size) {
- case 1:
- __asm__ __volatile__(LOCK_PREFIX "cmpxchgb %b1,%2"
- : "=a"(prev)
- : "q"(new), "m"(*__xg(ptr)), "0"(old)
- : "memory");
- return prev;
- case 2:
- __asm__ __volatile__(LOCK_PREFIX "cmpxchgw %w1,%2"
- : "=a"(prev)
- : "q"(new), "m"(*__xg(ptr)), "0"(old)
- : "memory");
- return prev;
- case 4:
- __asm__ __volatile__(LOCK_PREFIX "cmpxchgl %1,%2"
- : "=a"(prev)
- : "q"(new), "m"(*__xg(ptr)), "0"(old)
- : "memory");
- return prev;
- }
- return old;
-}
-
-#define cmpxchg(ptr,o,n)\
- ((__typeof__(*(ptr)))__cmpxchg((ptr),(unsigned long)(o),\
- (unsigned long)(n),sizeof(*(ptr))))
-
-#else
-/* Compiling for a 386 proper. Is it worth implementing via cli/sti? */
-#endif
-
-/*
- * Force strict CPU ordering.
- * And yes, this is required on UP too when we're talking
- * to devices.
- *
- * For now, "wmb()" doesn't actually do anything, as all
- * Intel CPU's follow what Intel calls a *Processor Order*,
- * in which all writes are seen in the program order even
- * outside the CPU.
- *
- * I expect future Intel CPU's to have a weaker ordering,
- * but I'd also expect them to finally get their act together
- * and add some real memory barriers if so.
- *
- * Some non intel clones support out of order store. wmb() ceases to be a
- * nop for these.
- */
-
-#define mb() __asm__ __volatile__ ("lock; addl $0,0(%%esp)": : :"memory")
-#define rmb() mb()
-
-#ifdef CONFIG_X86_OOSTORE
-#define wmb() __asm__ __volatile__ ("lock; addl $0,0(%%esp)": : :"memory")
-#else
-#define wmb() __asm__ __volatile__ ("": : :"memory")
-#endif
-
-#ifdef CONFIG_SMP
-#define smp_mb() mb()
-#define smp_rmb() rmb()
-#define smp_wmb() wmb()
-#else
-#define smp_mb() barrier()
-#define smp_rmb() barrier()
-#define smp_wmb() barrier()
-#endif
-
-#define set_mb(var, value) do { xchg(&var, value); } while (0)
-#define set_wmb(var, value) do { var = value; wmb(); } while (0)
-
-
-#define __save_flags(x) \
-do { \
- (x) = test_bit(EVENTS_MASTER_ENABLE_BIT, \
- &HYPERVISOR_shared_info->events_mask); \
- barrier(); \
-} while (0)
-
-#define __restore_flags(x) \
-do { \
- shared_info_t *_shared = HYPERVISOR_shared_info; \
- if (x) set_bit(EVENTS_MASTER_ENABLE_BIT, &_shared->events_mask); \
- barrier(); \
- if ( unlikely(_shared->events) && (x) ) do_hypervisor_callback(NULL); \
-} while (0)
-
-#define __cli() \
-do { \
- clear_bit(EVENTS_MASTER_ENABLE_BIT, &HYPERVISOR_shared_info->events_mask);\
- barrier(); \
-} while (0)
-
-#define __sti() \
-do { \
- shared_info_t *_shared = HYPERVISOR_shared_info; \
- set_bit(EVENTS_MASTER_ENABLE_BIT, &_shared->events_mask); \
- barrier(); \
- if ( unlikely(_shared->events) ) do_hypervisor_callback(NULL); \
-} while (0)
-
-#define safe_halt() ((void)0)
-
-#define __save_and_cli(x) do { __save_flags(x); __cli(); } while(0);
-#define __save_and_sti(x) do { __save_flags(x); __sti(); } while(0);
-
-#define local_irq_save(x) \
-do { \
- (x) = test_and_clear_bit(EVENTS_MASTER_ENABLE_BIT, \
- &HYPERVISOR_shared_info->events_mask); \
- barrier(); \
-} while (0)
-#define local_irq_restore(x) __restore_flags(x)
-#define local_irq_disable() __cli()
-#define local_irq_enable() __sti()
-
-
-#ifdef CONFIG_SMP
-#error no SMP
-extern void __global_cli(void);
-extern void __global_sti(void);
-extern unsigned long __global_save_flags(void);
-extern void __global_restore_flags(unsigned long);
-#define cli() __global_cli()
-#define sti() __global_sti()
-#define save_flags(x) ((x)=__global_save_flags())
-#define restore_flags(x) __global_restore_flags(x)
-#define save_and_cli(x) do { save_flags(x); cli(); } while(0);
-#define save_and_sti(x) do { save_flags(x); sti(); } while(0);
-
-#else
-
-#define cli() __cli()
-#define sti() __sti()
-#define save_flags(x) __save_flags(x)
-#define restore_flags(x) __restore_flags(x)
-#define save_and_cli(x) __save_and_cli(x)
-#define save_and_sti(x) __save_and_sti(x)
-
-#endif
-
-/*
- * disable hlt during certain critical i/o operations
- */
-#define HAVE_DISABLE_HLT
-void disable_hlt(void);
-void enable_hlt(void);
-
-extern unsigned long dmi_broken;
-extern int is_sony_vaio_laptop;
-
-#define BROKEN_ACPI_Sx 0x0001
-#define BROKEN_INIT_AFTER_S1 0x0002
-
-#endif
+++ /dev/null
-#ifndef _LINUX_MAJOR_H
-#define _LINUX_MAJOR_H
-
-/*
- * This file has definitions for major device numbers.
- * For the device number assignments, see Documentation/devices.txt.
- */
-
-/* limits */
-
-/*
- * Important: Don't change this to 256. Major number 255 is and must be
- * reserved for future expansion into a larger dev_t space.
- */
-#define MAX_CHRDEV 255
-#define MAX_BLKDEV 255
-
-#define UNNAMED_MAJOR 0
-#define MEM_MAJOR 1
-#define RAMDISK_MAJOR 1
-#define FLOPPY_MAJOR 2
-#define PTY_MASTER_MAJOR 2
-#define IDE0_MAJOR 3
-#define PTY_SLAVE_MAJOR 3
-#define HD_MAJOR IDE0_MAJOR
-#define TTY_MAJOR 4
-#define TTYAUX_MAJOR 5
-#define LP_MAJOR 6
-#define VCS_MAJOR 7
-#define LOOP_MAJOR 7
-#define SCSI_DISK0_MAJOR 8
-#define SCSI_TAPE_MAJOR 9
-#define MD_MAJOR 9
-#define MISC_MAJOR 10
-#define SCSI_CDROM_MAJOR 11
-#define MUX_MAJOR 11 /* PA-RISC only */
-#define QIC02_TAPE_MAJOR 12
-#define XT_DISK_MAJOR 13
-#define SOUND_MAJOR 14
-#define CDU31A_CDROM_MAJOR 15
-#define JOYSTICK_MAJOR 15
-#define GOLDSTAR_CDROM_MAJOR 16
-#define OPTICS_CDROM_MAJOR 17
-#define SANYO_CDROM_MAJOR 18
-#define CYCLADES_MAJOR 19
-#define CYCLADESAUX_MAJOR 20
-#define MITSUMI_X_CDROM_MAJOR 20
-#define MFM_ACORN_MAJOR 21 /* ARM Linux /dev/mfm */
-#define SCSI_GENERIC_MAJOR 21
-#define Z8530_MAJOR 34
-#define DIGI_MAJOR 23
-#define IDE1_MAJOR 22
-#define DIGICU_MAJOR 22
-#define MITSUMI_CDROM_MAJOR 23
-#define CDU535_CDROM_MAJOR 24
-#define STL_SERIALMAJOR 24
-#define MATSUSHITA_CDROM_MAJOR 25
-#define STL_CALLOUTMAJOR 25
-#define MATSUSHITA_CDROM2_MAJOR 26
-#define QIC117_TAPE_MAJOR 27
-#define MATSUSHITA_CDROM3_MAJOR 27
-#define MATSUSHITA_CDROM4_MAJOR 28
-#define STL_SIOMEMMAJOR 28
-#define ACSI_MAJOR 28
-#define AZTECH_CDROM_MAJOR 29
-#define GRAPHDEV_MAJOR 29 /* SparcLinux & Linux/68k /dev/fb */
-#define SHMIQ_MAJOR 85 /* Linux/mips, SGI /dev/shmiq */
-#define CM206_CDROM_MAJOR 32
-#define IDE2_MAJOR 33
-#define IDE3_MAJOR 34
-#define XPRAM_MAJOR 35 /* expanded storage on S/390 = "slow ram" */
- /* proposed by Peter */
-#define NETLINK_MAJOR 36
-#define PS2ESDI_MAJOR 36
-#define IDETAPE_MAJOR 37
-#define Z2RAM_MAJOR 37
-#define APBLOCK_MAJOR 38 /* AP1000 Block device */
-#define DDV_MAJOR 39 /* AP1000 DDV block device */
-#define NBD_MAJOR 43 /* Network block device */
-#define RISCOM8_NORMAL_MAJOR 48
-#define DAC960_MAJOR 48 /* 48..55 */
-#define RISCOM8_CALLOUT_MAJOR 49
-#define MKISS_MAJOR 55
-#define DSP56K_MAJOR 55 /* DSP56001 processor device */
-
-#define IDE4_MAJOR 56
-#define IDE5_MAJOR 57
-
-#define LVM_BLK_MAJOR 58 /* Logical Volume Manager */
-
-#define SCSI_DISK1_MAJOR 65
-#define SCSI_DISK2_MAJOR 66
-#define SCSI_DISK3_MAJOR 67
-#define SCSI_DISK4_MAJOR 68
-#define SCSI_DISK5_MAJOR 69
-#define SCSI_DISK6_MAJOR 70
-#define SCSI_DISK7_MAJOR 71
-
-
-#define COMPAQ_SMART2_MAJOR 72
-#define COMPAQ_SMART2_MAJOR1 73
-#define COMPAQ_SMART2_MAJOR2 74
-#define COMPAQ_SMART2_MAJOR3 75
-#define COMPAQ_SMART2_MAJOR4 76
-#define COMPAQ_SMART2_MAJOR5 77
-#define COMPAQ_SMART2_MAJOR6 78
-#define COMPAQ_SMART2_MAJOR7 79
-
-#define SPECIALIX_NORMAL_MAJOR 75
-#define SPECIALIX_CALLOUT_MAJOR 76
-
-#define COMPAQ_CISS_MAJOR 104
-#define COMPAQ_CISS_MAJOR1 105
-#define COMPAQ_CISS_MAJOR2 106
-#define COMPAQ_CISS_MAJOR3 107
-#define COMPAQ_CISS_MAJOR4 108
-#define COMPAQ_CISS_MAJOR5 109
-#define COMPAQ_CISS_MAJOR6 110
-#define COMPAQ_CISS_MAJOR7 111
-
-#define ATARAID_MAJOR 114
-
-#define DASD_MAJOR 94 /* Official assignations from Peter */
-
-#define MDISK_MAJOR 95 /* Official assignations from Peter */
-
-#define I2O_MAJOR 80 /* 80->87 */
-
-#define IDE6_MAJOR 88
-#define IDE7_MAJOR 89
-#define IDE8_MAJOR 90
-#define IDE9_MAJOR 91
-
-#define UBD_MAJOR 98
-
-#define AURORA_MAJOR 79
-
-#define JSFD_MAJOR 99
-
-#define PHONE_MAJOR 100
-
-#define LVM_CHAR_MAJOR 109 /* Logical Volume Manager */
-
-#define UMEM_MAJOR 116 /* http://www.umem.com/ Battery Backed RAM */
-
-#define UMEM_MAJOR 116 /* http://www.umem.com/ Battery Backed RAM */
-
-/*
- * XLVIRT supports 16 devices of <= 16 partitions each.
- * eg. xvda == (125, 0), xvdb == (125, 16), ...
- */
-#define XLVIRT_MAJOR 125
-
-#define RTF_MAJOR 150
-#define RAW_MAJOR 162
-
-#define USB_ACM_MAJOR 166
-#define USB_ACM_AUX_MAJOR 167
-#define USB_CHAR_MAJOR 180
-
-#define UNIX98_PTY_MASTER_MAJOR 128
-#define UNIX98_PTY_MAJOR_COUNT 8
-#define UNIX98_PTY_SLAVE_MAJOR (UNIX98_PTY_MASTER_MAJOR+UNIX98_PTY_MAJOR_COUNT)
-
-#define VXVM_MAJOR 199 /* VERITAS volume i/o driver */
-#define VXSPEC_MAJOR 200 /* VERITAS volume config driver */
-#define VXDMP_MAJOR 201 /* VERITAS volume multipath driver */
-
-#define MSR_MAJOR 202
-#define CPUID_MAJOR 203
-
-#define OSST_MAJOR 206 /* OnStream-SCx0 SCSI tape */
-
-#define IBM_TTY3270_MAJOR 227 /* Official allocations now */
-#define IBM_FS3270_MAJOR 228
-
-/*
- * Tests for SCSI devices.
- */
-
-#define SCSI_DISK_MAJOR(M) ((M) == SCSI_DISK0_MAJOR || \
- ((M) >= SCSI_DISK1_MAJOR && (M) <= SCSI_DISK7_MAJOR))
-
-#define SCSI_BLK_MAJOR(M) \
- (SCSI_DISK_MAJOR(M) \
- || (M) == SCSI_CDROM_MAJOR)
-
-static __inline__ int scsi_blk_major(int m) {
- return SCSI_BLK_MAJOR(m);
-}
-
-/*
- * Tests for IDE devices
- */
-#define IDE_DISK_MAJOR(M) ((M) == IDE0_MAJOR || (M) == IDE1_MAJOR || \
- (M) == IDE2_MAJOR || (M) == IDE3_MAJOR || \
- (M) == IDE4_MAJOR || (M) == IDE5_MAJOR || \
- (M) == IDE6_MAJOR || (M) == IDE7_MAJOR || \
- (M) == IDE8_MAJOR || (M) == IDE9_MAJOR)
-
-static __inline__ int ide_blk_major(int m)
-{
- return IDE_DISK_MAJOR(m);
-}
-
-#endif
+++ /dev/null
-/*
- * linux/include/linux/sunrpc/debug.h
- *
- * Debugging support for sunrpc module
- *
- * Copyright (C) 1996, Olaf Kirch <okir@monad.swb.de>
- */
-
-#ifndef _LINUX_SUNRPC_DEBUG_H_
-#define _LINUX_SUNRPC_DEBUG_H_
-
-#include <linux/config.h>
-
-#include <linux/timer.h>
-#include <linux/tqueue.h>
-
-/*
- * Enable RPC debugging/profiling.
- */
-/*#ifdef CONFIG_SYSCTL*/
-/*#define RPC_DEBUG*/
-/*#endif*/
-/* #define RPC_PROFILE */
-
-/*
- * RPC debug facilities
- */
-#define RPCDBG_XPRT 0x0001
-#define RPCDBG_CALL 0x0002
-#define RPCDBG_DEBUG 0x0004
-#define RPCDBG_NFS 0x0008
-#define RPCDBG_AUTH 0x0010
-#define RPCDBG_PMAP 0x0020
-#define RPCDBG_SCHED 0x0040
-#define RPCDBG_SVCSOCK 0x0100
-#define RPCDBG_SVCDSP 0x0200
-#define RPCDBG_MISC 0x0400
-#define RPCDBG_ALL 0x7fff
-
-#ifdef __KERNEL__
-
-/*
- * Debugging macros etc
- */
-#ifdef RPC_DEBUG
-extern unsigned int rpc_debug;
-extern unsigned int nfs_debug;
-extern unsigned int nfsd_debug;
-extern unsigned int nlm_debug;
-#endif
-
-#define dprintk(args...) dfprintk(FACILITY, ## args)
-
-#undef ifdebug
-#ifdef RPC_DEBUG
-# define ifdebug(fac) if (rpc_debug & RPCDBG_##fac)
-# define dfprintk(fac, args...) do { ifdebug(fac) printk(args); } while(0)
-# define RPC_IFDEBUG(x) x
-#else
-# define dfprintk(fac, args...) do ; while (0)
-# define RPC_IFDEBUG(x)
-#endif
-
-#ifdef RPC_PROFILE
-# define pprintk(args...) printk(## args)
-#else
-# define pprintk(args...) do ; while (0)
-#endif
-
-/*
- * Sysctl interface for RPC debugging
- */
-#ifdef RPC_DEBUG
-void rpc_register_sysctl(void);
-void rpc_unregister_sysctl(void);
-#endif
-
-#endif /* __KERNEL__ */
-
-/*
- * Declarations for the sysctl debug interface, which allows to read or
- * change the debug flags for rpc, nfs, nfsd, and lockd. Since the sunrpc
- * module currently registers its sysctl table dynamically, the sysctl path
- * for module FOO is <CTL_SUNRPC, CTL_FOODEBUG>.
- */
-#define CTL_SUNRPC 7249 /* arbitrary and hopefully unused */
-
-enum {
- CTL_RPCDEBUG = 1,
- CTL_NFSDEBUG,
- CTL_NFSDDEBUG,
- CTL_NLMDEBUG,
-};
-
-#endif /* _LINUX_SUNRPC_DEBUG_H_ */
+++ /dev/null
-#define __KERNEL_SYSCALLS__
-#include <linux/config.h>
-#include <linux/slab.h>
-#include <linux/devfs_fs_kernel.h>
-#include <linux/unistd.h>
-#include <linux/ctype.h>
-#include <linux/blk.h>
-#include <linux/fd.h>
-#include <linux/tty.h>
-#include <linux/init.h>
-
-#include <linux/nfs_fs.h>
-#include <linux/nfs_fs_sb.h>
-#include <linux/nfs_mount.h>
-#include <linux/minix_fs.h>
-#include <linux/ext2_fs.h>
-#include <linux/romfs_fs.h>
-
-#define BUILD_CRAMDISK
-
-extern int get_filesystem_list(char * buf);
-
-extern asmlinkage long sys_mount(char *dev_name, char *dir_name, char *type,
- unsigned long flags, void *data);
-extern asmlinkage long sys_mkdir(const char *name, int mode);
-extern asmlinkage long sys_chdir(const char *name);
-extern asmlinkage long sys_fchdir(int fd);
-extern asmlinkage long sys_chroot(const char *name);
-extern asmlinkage long sys_unlink(const char *name);
-extern asmlinkage long sys_symlink(const char *old, const char *new);
-extern asmlinkage long sys_mknod(const char *name, int mode, dev_t dev);
-extern asmlinkage long sys_umount(char *name, int flags);
-extern asmlinkage long sys_ioctl(int fd, int cmd, unsigned long arg);
-
-#ifdef CONFIG_BLK_DEV_INITRD
-unsigned int real_root_dev; /* do_proc_dointvec cannot handle kdev_t */
-static int __initdata mount_initrd = 1;
-
-static int __init no_initrd(char *str)
-{
- mount_initrd = 0;
- return 1;
-}
-
-__setup("noinitrd", no_initrd);
-#else
-static int __initdata mount_initrd = 0;
-#endif
-
-int __initdata rd_doload; /* 1 = load RAM disk, 0 = don't load */
-
-int root_mountflags = MS_RDONLY | MS_VERBOSE;
-static char root_device_name[64];
-
-/* this is initialized in init/main.c */
-kdev_t ROOT_DEV;
-
-static int do_devfs = 0;
-
-static int __init load_ramdisk(char *str)
-{
- rd_doload = simple_strtol(str,NULL,0) & 3;
- return 1;
-}
-__setup("load_ramdisk=", load_ramdisk);
-
-static int __init readonly(char *str)
-{
- if (*str)
- return 0;
- root_mountflags |= MS_RDONLY;
- return 1;
-}
-
-static int __init readwrite(char *str)
-{
- if (*str)
- return 0;
- root_mountflags &= ~MS_RDONLY;
- return 1;
-}
-
-__setup("ro", readonly);
-__setup("rw", readwrite);
-
-static struct dev_name_struct {
- const char *name;
- const int num;
-} root_dev_names[] __initdata = {
- { "nfs", 0x00ff },
- { "hda", 0x0300 },
- { "hdb", 0x0340 },
- { "loop", 0x0700 },
- { "hdc", 0x1600 },
- { "hdd", 0x1640 },
- { "hde", 0x2100 },
- { "hdf", 0x2140 },
- { "hdg", 0x2200 },
- { "hdh", 0x2240 },
- { "hdi", 0x3800 },
- { "hdj", 0x3840 },
- { "hdk", 0x3900 },
- { "hdl", 0x3940 },
- { "hdm", 0x5800 },
- { "hdn", 0x5840 },
- { "hdo", 0x5900 },
- { "hdp", 0x5940 },
- { "hdq", 0x5A00 },
- { "hdr", 0x5A40 },
- { "hds", 0x5B00 },
- { "hdt", 0x5B40 },
- { "sda", 0x0800 },
- { "sdb", 0x0810 },
- { "sdc", 0x0820 },
- { "sdd", 0x0830 },
- { "sde", 0x0840 },
- { "sdf", 0x0850 },
- { "sdg", 0x0860 },
- { "sdh", 0x0870 },
- { "sdi", 0x0880 },
- { "sdj", 0x0890 },
- { "sdk", 0x08a0 },
- { "sdl", 0x08b0 },
- { "sdm", 0x08c0 },
- { "sdn", 0x08d0 },
- { "sdo", 0x08e0 },
- { "sdp", 0x08f0 },
- { "ada", 0x1c00 },
- { "adb", 0x1c10 },
- { "adc", 0x1c20 },
- { "add", 0x1c30 },
- { "ade", 0x1c40 },
- { "fd", 0x0200 },
- { "md", 0x0900 },
- { "xda", 0x0d00 },
- { "xdb", 0x0d40 },
- { "ram", 0x0100 },
- { "scd", 0x0b00 },
- { "mcd", 0x1700 },
- { "cdu535", 0x1800 },
- { "sonycd", 0x1800 },
- { "aztcd", 0x1d00 },
- { "cm206cd", 0x2000 },
- { "gscd", 0x1000 },
- { "sbpcd", 0x1900 },
- { "eda", 0x2400 },
- { "edb", 0x2440 },
- { "pda", 0x2d00 },
- { "pdb", 0x2d10 },
- { "pdc", 0x2d20 },
- { "pdd", 0x2d30 },
- { "pcd", 0x2e00 },
- { "pf", 0x2f00 },
- { "apblock", APBLOCK_MAJOR << 8},
- { "ddv", DDV_MAJOR << 8},
- { "jsfd", JSFD_MAJOR << 8},
-#if defined(CONFIG_ARCH_S390)
- { "dasda", (DASD_MAJOR << MINORBITS) },
- { "dasdb", (DASD_MAJOR << MINORBITS) + (1 << 2) },
- { "dasdc", (DASD_MAJOR << MINORBITS) + (2 << 2) },
- { "dasdd", (DASD_MAJOR << MINORBITS) + (3 << 2) },
- { "dasde", (DASD_MAJOR << MINORBITS) + (4 << 2) },
- { "dasdf", (DASD_MAJOR << MINORBITS) + (5 << 2) },
- { "dasdg", (DASD_MAJOR << MINORBITS) + (6 << 2) },
- { "dasdh", (DASD_MAJOR << MINORBITS) + (7 << 2) },
-#endif
-#if defined(CONFIG_BLK_CPQ_DA) || defined(CONFIG_BLK_CPQ_DA_MODULE)
- { "ida/c0d0p",0x4800 },
- { "ida/c0d1p",0x4810 },
- { "ida/c0d2p",0x4820 },
- { "ida/c0d3p",0x4830 },
- { "ida/c0d4p",0x4840 },
- { "ida/c0d5p",0x4850 },
- { "ida/c0d6p",0x4860 },
- { "ida/c0d7p",0x4870 },
- { "ida/c0d8p",0x4880 },
- { "ida/c0d9p",0x4890 },
- { "ida/c0d10p",0x48A0 },
- { "ida/c0d11p",0x48B0 },
- { "ida/c0d12p",0x48C0 },
- { "ida/c0d13p",0x48D0 },
- { "ida/c0d14p",0x48E0 },
- { "ida/c0d15p",0x48F0 },
- { "ida/c1d0p",0x4900 },
- { "ida/c2d0p",0x4A00 },
- { "ida/c3d0p",0x4B00 },
- { "ida/c4d0p",0x4C00 },
- { "ida/c5d0p",0x4D00 },
- { "ida/c6d0p",0x4E00 },
- { "ida/c7d0p",0x4F00 },
-#endif
-#if defined(CONFIG_BLK_CPQ_CISS_DA) || defined(CONFIG_BLK_CPQ_CISS_DA_MODULE)
- { "cciss/c0d0p",0x6800 },
- { "cciss/c0d1p",0x6810 },
- { "cciss/c0d2p",0x6820 },
- { "cciss/c0d3p",0x6830 },
- { "cciss/c0d4p",0x6840 },
- { "cciss/c0d5p",0x6850 },
- { "cciss/c0d6p",0x6860 },
- { "cciss/c0d7p",0x6870 },
- { "cciss/c0d8p",0x6880 },
- { "cciss/c0d9p",0x6890 },
- { "cciss/c0d10p",0x68A0 },
- { "cciss/c0d11p",0x68B0 },
- { "cciss/c0d12p",0x68C0 },
- { "cciss/c0d13p",0x68D0 },
- { "cciss/c0d14p",0x68E0 },
- { "cciss/c0d15p",0x68F0 },
- { "cciss/c1d0p",0x6900 },
- { "cciss/c2d0p",0x6A00 },
- { "cciss/c3d0p",0x6B00 },
- { "cciss/c4d0p",0x6C00 },
- { "cciss/c5d0p",0x6D00 },
- { "cciss/c6d0p",0x6E00 },
- { "cciss/c7d0p",0x6F00 },
-#endif
- { "ataraid/d0p",0x7200 },
- { "ataraid/d1p",0x7210 },
- { "ataraid/d2p",0x7220 },
- { "ataraid/d3p",0x7230 },
- { "ataraid/d4p",0x7240 },
- { "ataraid/d5p",0x7250 },
- { "ataraid/d6p",0x7260 },
- { "ataraid/d7p",0x7270 },
- { "ataraid/d8p",0x7280 },
- { "ataraid/d9p",0x7290 },
- { "ataraid/d10p",0x72A0 },
- { "ataraid/d11p",0x72B0 },
- { "ataraid/d12p",0x72C0 },
- { "ataraid/d13p",0x72D0 },
- { "ataraid/d14p",0x72E0 },
- { "ataraid/d15p",0x72F0 },
-#if defined(CONFIG_XENOLINUX_BLOCK)
- { "xvda", 0x7D00 }, { "xvdb", 0x7D10 },
- { "xvdc", 0x7D20 }, { "xvdd", 0x7D30 },
- { "xvde", 0x7D40 }, { "xvdf", 0x7D50 },
- { "xvdg", 0x7D60 }, { "xvdh", 0x7D70 },
- { "xvdi", 0x7D80 }, { "xvdj", 0x7D90 },
- { "xvdk", 0x7DA0 }, { "xvdl", 0x7DB0 },
- { "xvdm", 0x7DC0 }, { "xvdn", 0x7DD0 },
- { "xvdo", 0x7DE0 }, { "xvdp", 0x7DF0 },
-#endif
- { "nftla", 0x5d00 },
- { "nftlb", 0x5d10 },
- { "nftlc", 0x5d20 },
- { "nftld", 0x5d30 },
- { "ftla", 0x2c00 },
- { "ftlb", 0x2c08 },
- { "ftlc", 0x2c10 },
- { "ftld", 0x2c18 },
- { "mtdblock", 0x1f00 },
- { NULL, 0 }
-};
-
-kdev_t __init name_to_kdev_t(char *line)
-{
- int base = 0, offs;
- char *end;
-
- if (strncmp(line,"/dev/",5) == 0) {
- struct dev_name_struct *dev = root_dev_names;
- line += 5;
- do {
- int len = strlen(dev->name);
- if (strncmp(line,dev->name,len) == 0) {
- line += len;
- base = dev->num;
- break;
- }
- dev++;
- } while (dev->name);
- }
- offs = simple_strtoul(line, &end, base?10:16);
- if (*end)
- offs = 0;
- return to_kdev_t(base + offs);
-}
-
-static int __init root_dev_setup(char *line)
-{
- int i;
- char ch;
-
- ROOT_DEV = name_to_kdev_t(line);
- memset (root_device_name, 0, sizeof root_device_name);
- if (strncmp (line, "/dev/", 5) == 0) line += 5;
- for (i = 0; i < sizeof root_device_name - 1; ++i)
- {
- ch = line[i];
- if ( isspace (ch) || (ch == ',') || (ch == '\0') ) break;
- root_device_name[i] = ch;
- }
- return 1;
-}
-
-__setup("root=", root_dev_setup);
-
-static char * __initdata root_mount_data;
-static int __init root_data_setup(char *str)
-{
- root_mount_data = str;
- return 1;
-}
-
-static char * __initdata root_fs_names;
-static int __init fs_names_setup(char *str)
-{
- root_fs_names = str;
- return 1;
-}
-
-__setup("rootflags=", root_data_setup);
-__setup("rootfstype=", fs_names_setup);
-
-static void __init get_fs_names(char *page)
-{
- char *s = page;
-
- if (root_fs_names) {
- strcpy(page, root_fs_names);
- while (*s++) {
- if (s[-1] == ',')
- s[-1] = '\0';
- }
- } else {
- int len = get_filesystem_list(page);
- char *p, *next;
-
- page[len] = '\0';
- for (p = page-1; p; p = next) {
- next = strchr(++p, '\n');
- if (*p++ != '\t')
- continue;
- while ((*s++ = *p++) != '\n')
- ;
- s[-1] = '\0';
- }
- }
- *s = '\0';
-}
-static void __init mount_block_root(char *name, int flags)
-{
- char *fs_names = __getname();
- char *p;
-
- get_fs_names(fs_names);
-retry:
- for (p = fs_names; *p; p += strlen(p)+1) {
- int err = sys_mount(name, "/root", p, flags, root_mount_data);
- switch (err) {
- case 0:
- goto out;
- case -EACCES:
- flags |= MS_RDONLY;
- goto retry;
- case -EINVAL:
- continue;
- }
- /*
- * Allow the user to distinguish between failed open
- * and bad superblock on root device.
- */
- printk ("VFS: Cannot open root device \"%s\" or %s\n",
- root_device_name, kdevname (ROOT_DEV));
- printk ("Please append a correct \"root=\" boot option\n");
- panic("VFS: Unable to mount root fs on %s",
- kdevname(ROOT_DEV));
- }
- panic("VFS: Unable to mount root fs on %s", kdevname(ROOT_DEV));
-out:
- putname(fs_names);
- sys_chdir("/root");
- ROOT_DEV = current->fs->pwdmnt->mnt_sb->s_dev;
- printk("VFS: Mounted root (%s filesystem)%s.\n",
- current->fs->pwdmnt->mnt_sb->s_type->name,
- (current->fs->pwdmnt->mnt_sb->s_flags & MS_RDONLY) ? " readonly" : "");
-}
-
-#ifdef CONFIG_ROOT_NFS
-static int __init mount_nfs_root(void)
-{
- void *data = nfs_root_data();
-
- if (data && sys_mount("/dev/root","/root","nfs",root_mountflags,data) == 0)
- return 1;
- return 0;
-}
-#endif
-
-static int __init create_dev(char *name, kdev_t dev, char *devfs_name)
-{
- void *handle;
- char path[64];
- int n;
-
- sys_unlink(name);
- if (!do_devfs)
- return sys_mknod(name, S_IFBLK|0600, kdev_t_to_nr(dev));
-
- handle = devfs_find_handle(NULL, dev ? NULL : devfs_name,
- MAJOR(dev), MINOR(dev), DEVFS_SPECIAL_BLK, 1);
- if (!handle)
- return -1;
- n = devfs_generate_path(handle, path + 5, sizeof (path) - 5);
- if (n < 0)
- return -1;
- return sys_symlink(path + n + 5, name);
-}
-
-#if defined(CONFIG_BLK_DEV_RAM) || defined(CONFIG_BLK_DEV_FD)
-static void __init change_floppy(char *fmt, ...)
-{
- struct termios termios;
- char buf[80];
- char c;
- int fd;
- va_list args;
- va_start(args, fmt);
- vsprintf(buf, fmt, args);
- va_end(args);
- fd = open("/dev/root", O_RDWR | O_NDELAY, 0);
- if (fd >= 0) {
- sys_ioctl(fd, FDEJECT, 0);
- close(fd);
- }
- printk(KERN_NOTICE "VFS: Insert %s and press ENTER\n", buf);
- fd = open("/dev/console", O_RDWR, 0);
- if (fd >= 0) {
- sys_ioctl(fd, TCGETS, (long)&termios);
- termios.c_lflag &= ~ICANON;
- sys_ioctl(fd, TCSETSF, (long)&termios);
- read(fd, &c, 1);
- termios.c_lflag |= ICANON;
- sys_ioctl(fd, TCSETSF, (long)&termios);
- close(fd);
- }
-}
-#endif
-
-#ifdef CONFIG_BLK_DEV_RAM
-
-int __initdata rd_prompt = 1; /* 1 = prompt for RAM disk, 0 = don't prompt */
-
-static int __init prompt_ramdisk(char *str)
-{
- rd_prompt = simple_strtol(str,NULL,0) & 1;
- return 1;
-}
-__setup("prompt_ramdisk=", prompt_ramdisk);
-
-int __initdata rd_image_start; /* starting block # of image */
-
-static int __init ramdisk_start_setup(char *str)
-{
- rd_image_start = simple_strtol(str,NULL,0);
- return 1;
-}
-__setup("ramdisk_start=", ramdisk_start_setup);
-
-static int __init crd_load(int in_fd, int out_fd);
-
-/*
- * This routine tries to find a RAM disk image to load, and returns the
- * number of blocks to read for a non-compressed image, 0 if the image
- * is a compressed image, and -1 if an image with the right magic
- * numbers could not be found.
- *
- * We currently check for the following magic numbers:
- * minix
- * ext2
- * romfs
- * gzip
- */
-static int __init
-identify_ramdisk_image(int fd, int start_block)
-{
- const int size = 512;
- struct minix_super_block *minixsb;
- struct ext2_super_block *ext2sb;
- struct romfs_super_block *romfsb;
- int nblocks = -1;
- unsigned char *buf;
-
- buf = kmalloc(size, GFP_KERNEL);
- if (buf == 0)
- return -1;
-
- minixsb = (struct minix_super_block *) buf;
- ext2sb = (struct ext2_super_block *) buf;
- romfsb = (struct romfs_super_block *) buf;
- memset(buf, 0xe5, size);
-
- /*
- * Read block 0 to test for gzipped kernel
- */
- lseek(fd, start_block * BLOCK_SIZE, 0);
- read(fd, buf, size);
-
- /*
- * If it matches the gzip magic numbers, return -1
- */
- if (buf[0] == 037 && ((buf[1] == 0213) || (buf[1] == 0236))) {
- printk(KERN_NOTICE
- "RAMDISK: Compressed image found at block %d\n",
- start_block);
- nblocks = 0;
- goto done;
- }
-
- /* romfs is at block zero too */
- if (romfsb->word0 == ROMSB_WORD0 &&
- romfsb->word1 == ROMSB_WORD1) {
- printk(KERN_NOTICE
- "RAMDISK: romfs filesystem found at block %d\n",
- start_block);
- nblocks = (ntohl(romfsb->size)+BLOCK_SIZE-1)>>BLOCK_SIZE_BITS;
- goto done;
- }
-
- /*
- * Read block 1 to test for minix and ext2 superblock
- */
- lseek(fd, (start_block+1) * BLOCK_SIZE, 0);
- read(fd, buf, size);
-
- /* Try minix */
- if (minixsb->s_magic == MINIX_SUPER_MAGIC ||
- minixsb->s_magic == MINIX_SUPER_MAGIC2) {
- printk(KERN_NOTICE
- "RAMDISK: Minix filesystem found at block %d\n",
- start_block);
- nblocks = minixsb->s_nzones << minixsb->s_log_zone_size;
- goto done;
- }
-
- /* Try ext2 */
- if (ext2sb->s_magic == cpu_to_le16(EXT2_SUPER_MAGIC)) {
- printk(KERN_NOTICE
- "RAMDISK: ext2 filesystem found at block %d\n",
- start_block);
- nblocks = le32_to_cpu(ext2sb->s_blocks_count);
- goto done;
- }
-
- printk(KERN_NOTICE
- "RAMDISK: Couldn't find valid RAM disk image starting at %d.\n",
- start_block);
-
-done:
- lseek(fd, start_block * BLOCK_SIZE, 0);
- kfree(buf);
- return nblocks;
-}
-#endif
-
-static int __init rd_load_image(char *from)
-{
- int res = 0;
-
-#ifdef CONFIG_BLK_DEV_RAM
- int in_fd, out_fd;
- unsigned long rd_blocks, devblocks;
- int nblocks, i;
- char *buf;
- unsigned short rotate = 0;
-#if !defined(CONFIG_ARCH_S390) && !defined(CONFIG_PPC_ISERIES)
- char rotator[4] = { '|' , '/' , '-' , '\\' };
-#endif
-
- out_fd = open("/dev/ram", O_RDWR, 0);
- if (out_fd < 0)
- goto out;
-
- in_fd = open(from, O_RDONLY, 0);
- if (in_fd < 0)
- goto noclose_input;
-
- nblocks = identify_ramdisk_image(in_fd, rd_image_start);
- if (nblocks < 0)
- goto done;
-
- if (nblocks == 0) {
-#ifdef BUILD_CRAMDISK
- if (crd_load(in_fd, out_fd) == 0)
- goto successful_load;
-#else
- printk(KERN_NOTICE
- "RAMDISK: Kernel does not support compressed "
- "RAM disk images\n");
-#endif
- goto done;
- }
-
- /*
- * NOTE NOTE: nblocks suppose that the blocksize is BLOCK_SIZE, so
- * rd_load_image will work only with filesystem BLOCK_SIZE wide!
- * So make sure to use 1k blocksize while generating ext2fs
- * ramdisk-images.
- */
- if (sys_ioctl(out_fd, BLKGETSIZE, (unsigned long)&rd_blocks) < 0)
- rd_blocks = 0;
- else
- rd_blocks >>= 1;
-
- if (nblocks > rd_blocks) {
- printk("RAMDISK: image too big! (%d/%lu blocks)\n",
- nblocks, rd_blocks);
- goto done;
- }
-
- /*
- * OK, time to copy in the data
- */
- buf = kmalloc(BLOCK_SIZE, GFP_KERNEL);
- if (buf == 0) {
- printk(KERN_ERR "RAMDISK: could not allocate buffer\n");
- goto done;
- }
-
- if (sys_ioctl(in_fd, BLKGETSIZE, (unsigned long)&devblocks) < 0)
- devblocks = 0;
- else
- devblocks >>= 1;
-
- if (strcmp(from, "/dev/initrd") == 0)
- devblocks = nblocks;
-
- if (devblocks == 0) {
- printk(KERN_ERR "RAMDISK: could not determine device size\n");
- goto done;
- }
-
- printk(KERN_NOTICE "RAMDISK: Loading %d blocks [%ld disk%s] into ram disk... ",
- nblocks, ((nblocks-1)/devblocks)+1, nblocks>devblocks ? "s" : "");
- for (i=0; i < nblocks; i++) {
- if (i && (i % devblocks == 0)) {
- printk("done disk #%ld.\n", i/devblocks);
- rotate = 0;
- if (close(in_fd)) {
- printk("Error closing the disk.\n");
- goto noclose_input;
- }
- change_floppy("disk #%d", i/devblocks+1);
- in_fd = open(from, O_RDONLY, 0);
- if (in_fd < 0) {
- printk("Error opening disk.\n");
- goto noclose_input;
- }
- printk("Loading disk #%ld... ", i/devblocks+1);
- }
- read(in_fd, buf, BLOCK_SIZE);
- write(out_fd, buf, BLOCK_SIZE);
-#if !defined(CONFIG_ARCH_S390) && !defined(CONFIG_PPC_ISERIES)
- if (!(i % 16)) {
- printk("%c\b", rotator[rotate & 0x3]);
- rotate++;
- }
-#endif
- }
- printk("done.\n");
- kfree(buf);
-
-successful_load:
- res = 1;
-done:
- close(in_fd);
-noclose_input:
- close(out_fd);
-out:
- sys_unlink("/dev/ram");
-#endif
- return res;
-}
-
-static int __init rd_load_disk(int n)
-{
-#ifdef CONFIG_BLK_DEV_RAM
- if (rd_prompt)
- change_floppy("root floppy disk to be loaded into RAM disk");
- create_dev("/dev/ram", MKDEV(RAMDISK_MAJOR, n), NULL);
-#endif
- return rd_load_image("/dev/root");
-}
-
-#ifdef CONFIG_DEVFS_FS
-
-static void __init convert_name(char *prefix, char *name, char *p, int part)
-{
- int host, bus, target, lun;
- char dest[64];
- char src[64];
- char *base = p - 1;
-
- /* Decode "c#b#t#u#" */
- if (*p++ != 'c')
- return;
- host = simple_strtol(p, &p, 10);
- if (*p++ != 'b')
- return;
- bus = simple_strtol(p, &p, 10);
- if (*p++ != 't')
- return;
- target = simple_strtol(p, &p, 10);
- if (*p++ != 'u')
- return;
- lun = simple_strtol(p, &p, 10);
- if (!part)
- sprintf(dest, "%s/host%d/bus%d/target%d/lun%d",
- prefix, host, bus, target, lun);
- else if (*p++ == 'p')
- sprintf(dest, "%s/host%d/bus%d/target%d/lun%d/part%s",
- prefix, host, bus, target, lun, p);
- else
- sprintf(dest, "%s/host%d/bus%d/target%d/lun%d/disc",
- prefix, host, bus, target, lun);
- *base = '\0';
- sprintf(src, "/dev/%s", name);
- sys_mkdir(src, 0755);
- *base = '/';
- sprintf(src, "/dev/%s", name);
- sys_symlink(dest, src);
-}
-
-static void __init devfs_make_root(char *name)
-{
-
- if (!strncmp(name, "sd/", 3))
- convert_name("../scsi", name, name+3, 1);
- else if (!strncmp(name, "sr/", 3))
- convert_name("../scsi", name, name+3, 0);
- else if (!strncmp(name, "ide/hd/", 7))
- convert_name("..", name, name + 7, 1);
- else if (!strncmp(name, "ide/cd/", 7))
- convert_name("..", name, name + 7, 0);
-}
-#else
-static void __init devfs_make_root(char *name)
-{
-}
-#endif
-
-static void __init mount_root(void)
-{
-#ifdef CONFIG_ROOT_NFS
- if (MAJOR(ROOT_DEV) == UNNAMED_MAJOR) {
- if (mount_nfs_root()) {
- sys_chdir("/root");
- ROOT_DEV = current->fs->pwdmnt->mnt_sb->s_dev;
- printk("VFS: Mounted root (nfs filesystem).\n");
- return;
- }
- printk(KERN_ERR "VFS: Unable to mount root fs via NFS, trying floppy.\n");
- ROOT_DEV = MKDEV(FLOPPY_MAJOR, 0);
- }
-#endif
-printk("root_device_name = %s\n",root_device_name);
- devfs_make_root(root_device_name);
- create_dev("/dev/root", ROOT_DEV, root_device_name);
-#ifdef CONFIG_BLK_DEV_FD
- if (MAJOR(ROOT_DEV) == FLOPPY_MAJOR) {
- /* rd_doload is 2 for a dual initrd/ramload setup */
- if (rd_doload==2) {
- if (rd_load_disk(1)) {
- ROOT_DEV = MKDEV(RAMDISK_MAJOR, 1);
- create_dev("/dev/root", ROOT_DEV, NULL);
- }
- } else
- change_floppy("root floppy");
- }
-#endif
- mount_block_root("/dev/root", root_mountflags);
-}
-
-#ifdef CONFIG_BLK_DEV_INITRD
-static int old_fd, root_fd;
-static int do_linuxrc(void * shell)
-{
- static char *argv[] = { "linuxrc", NULL, };
- extern char * envp_init[];
-
- close(old_fd);
- close(root_fd);
- close(0);
- close(1);
- close(2);
- setsid();
- (void) open("/dev/console",O_RDWR,0);
- (void) dup(0);
- (void) dup(0);
- return execve(shell, argv, envp_init);
-}
-
-#endif
-
-static void __init handle_initrd(void)
-{
-#ifdef CONFIG_BLK_DEV_INITRD
- int ram0 = kdev_t_to_nr(MKDEV(RAMDISK_MAJOR,0));
- int error;
- int i, pid;
-
- create_dev("/dev/root.old", ram0, NULL);
- /* mount initrd on rootfs' /root */
- mount_block_root("/dev/root.old", root_mountflags & ~MS_RDONLY);
- sys_mkdir("/old", 0700);
- root_fd = open("/", 0, 0);
- old_fd = open("/old", 0, 0);
- /* move initrd over / and chdir/chroot in initrd root */
- sys_chdir("/root");
- sys_mount(".", "/", NULL, MS_MOVE, NULL);
- sys_chroot(".");
- mount_devfs_fs ();
-
- pid = kernel_thread(do_linuxrc, "/linuxrc", SIGCHLD);
- if (pid > 0) {
- while (pid != wait(&i))
- yield();
- }
-
- /* move initrd to rootfs' /old */
- sys_fchdir(old_fd);
- sys_mount("/", ".", NULL, MS_MOVE, NULL);
- /* switch root and cwd back to / of rootfs */
- sys_fchdir(root_fd);
- sys_chroot(".");
- sys_umount("/old/dev", 0);
-
- if (real_root_dev == ram0) {
- sys_chdir("/old");
- return;
- }
-
- ROOT_DEV = real_root_dev;
- mount_root();
-
- printk(KERN_NOTICE "Trying to move old root to /initrd ... ");
- error = sys_mount("/old", "/root/initrd", NULL, MS_MOVE, NULL);
- if (!error)
- printk("okay\n");
- else {
- int fd = open("/dev/root.old", O_RDWR, 0);
- printk("failed\n");
- printk(KERN_NOTICE "Unmounting old root\n");
- sys_umount("/old", MNT_DETACH);
- printk(KERN_NOTICE "Trying to free ramdisk memory ... ");
- if (fd < 0) {
- error = fd;
- } else {
- error = sys_ioctl(fd, BLKFLSBUF, 0);
- close(fd);
- }
- printk(!error ? "okay\n" : "failed\n");
- }
-#endif
-}
-
-static int __init initrd_load(void)
-{
-#ifdef CONFIG_BLK_DEV_INITRD
- create_dev("/dev/ram", MKDEV(RAMDISK_MAJOR, 0), NULL);
- create_dev("/dev/initrd", MKDEV(RAMDISK_MAJOR, INITRD_MINOR), NULL);
-#endif
- return rd_load_image("/dev/initrd");
-}
-
-/*
- * Prepare the namespace - decide what/where to mount, load ramdisks, etc.
- */
-void prepare_namespace(void)
-{
- int is_floppy = MAJOR(ROOT_DEV) == FLOPPY_MAJOR;
-#ifdef CONFIG_ALL_PPC
- extern void arch_discover_root(void);
- arch_discover_root();
-#endif /* CONFIG_ALL_PPC */
-#ifdef CONFIG_BLK_DEV_INITRD
- if (!initrd_start)
- mount_initrd = 0;
- real_root_dev = ROOT_DEV;
-#endif
- sys_mkdir("/dev", 0700);
- sys_mkdir("/root", 0700);
- sys_mknod("/dev/console", S_IFCHR|0600, MKDEV(TTYAUX_MAJOR, 1));
-#ifdef CONFIG_DEVFS_FS
- sys_mount("devfs", "/dev", "devfs", 0, NULL);
- do_devfs = 1;
-#endif
-
- create_dev("/dev/root", ROOT_DEV, NULL);
- if (mount_initrd) {
- if (initrd_load() && ROOT_DEV != MKDEV(RAMDISK_MAJOR, 0)) {
- handle_initrd();
- goto out;
- }
- } else if (is_floppy && rd_doload && rd_load_disk(0))
- ROOT_DEV = MKDEV(RAMDISK_MAJOR, 0);
- mount_root();
-out:
- sys_umount("/dev", 0);
- sys_mount(".", "/", NULL, MS_MOVE, NULL);
- sys_chroot(".");
- mount_devfs_fs ();
-}
-
-#if defined(BUILD_CRAMDISK) && defined(CONFIG_BLK_DEV_RAM)
-
-/*
- * gzip declarations
- */
-
-#define OF(args) args
-
-#ifndef memzero
-#define memzero(s, n) memset ((s), 0, (n))
-#endif
-
-typedef unsigned char uch;
-typedef unsigned short ush;
-typedef unsigned long ulg;
-
-#define INBUFSIZ 4096
-#define WSIZE 0x8000 /* window size--must be a power of two, and */
- /* at least 32K for zip's deflate method */
-
-static uch *inbuf;
-static uch *window;
-
-static unsigned insize; /* valid bytes in inbuf */
-static unsigned inptr; /* index of next byte to be processed in inbuf */
-static unsigned outcnt; /* bytes in output buffer */
-static int exit_code;
-static long bytes_out;
-static int crd_infd, crd_outfd;
-
-#define get_byte() (inptr < insize ? inbuf[inptr++] : fill_inbuf())
-
-/* Diagnostic functions (stubbed out) */
-#define Assert(cond,msg)
-#define Trace(x)
-#define Tracev(x)
-#define Tracevv(x)
-#define Tracec(c,x)
-#define Tracecv(c,x)
-
-#define STATIC static
-
-static int fill_inbuf(void);
-static void flush_window(void);
-static void *malloc(int size);
-static void free(void *where);
-static void error(char *m);
-static void gzip_mark(void **);
-static void gzip_release(void **);
-
-#include "../lib/inflate.c"
-
-static void __init *malloc(int size)
-{
- return kmalloc(size, GFP_KERNEL);
-}
-
-static void __init free(void *where)
-{
- kfree(where);
-}
-
-static void __init gzip_mark(void **ptr)
-{
-}
-
-static void __init gzip_release(void **ptr)
-{
-}
-
-
-/* ===========================================================================
- * Fill the input buffer. This is called only when the buffer is empty
- * and at least one byte is really needed.
- */
-static int __init fill_inbuf(void)
-{
- if (exit_code) return -1;
-
- insize = read(crd_infd, inbuf, INBUFSIZ);
- if (insize == 0) return -1;
-
- inptr = 1;
-
- return inbuf[0];
-}
-
-/* ===========================================================================
- * Write the output window window[0..outcnt-1] and update crc and bytes_out.
- * (Used for the decompressed data only.)
- */
-static void __init flush_window(void)
-{
- ulg c = crc; /* temporary variable */
- unsigned n;
- uch *in, ch;
-
- write(crd_outfd, window, outcnt);
- in = window;
- for (n = 0; n < outcnt; n++) {
- ch = *in++;
- c = crc_32_tab[((int)c ^ ch) & 0xff] ^ (c >> 8);
- }
- crc = c;
- bytes_out += (ulg)outcnt;
- outcnt = 0;
-}
-
-static void __init error(char *x)
-{
- printk(KERN_ERR "%s", x);
- exit_code = 1;
-}
-
-static int __init crd_load(int in_fd, int out_fd)
-{
- int result;
-
- insize = 0; /* valid bytes in inbuf */
- inptr = 0; /* index of next byte to be processed in inbuf */
- outcnt = 0; /* bytes in output buffer */
- exit_code = 0;
- bytes_out = 0;
- crc = (ulg)0xffffffffL; /* shift register contents */
-
- crd_infd = in_fd;
- crd_outfd = out_fd;
- inbuf = kmalloc(INBUFSIZ, GFP_KERNEL);
- if (inbuf == 0) {
- printk(KERN_ERR "RAMDISK: Couldn't allocate gzip buffer\n");
- return -1;
- }
- window = kmalloc(WSIZE, GFP_KERNEL);
- if (window == 0) {
- printk(KERN_ERR "RAMDISK: Couldn't allocate gzip window\n");
- kfree(inbuf);
- return -1;
- }
- makecrc();
- result = gunzip();
- kfree(inbuf);
- kfree(window);
- return result;
-}
-
-#endif /* BUILD_CRAMDISK && CONFIG_BLK_DEV_RAM */
+++ /dev/null
-/*
- * linux/kernel/panic.c
- *
- * Copyright (C) 1991, 1992 Linus Torvalds
- */
-
-/*
- * This function is used through-out the kernel (including mm and fs)
- * to indicate a major problem.
- */
-#include <linux/config.h>
-#include <linux/sched.h>
-#include <linux/delay.h>
-#include <linux/reboot.h>
-#include <linux/notifier.h>
-#include <linux/init.h>
-#include <linux/sysrq.h>
-#include <linux/interrupt.h>
-
-asmlinkage void sys_sync(void); /* it's really int */
-
-int panic_timeout;
-
-struct notifier_block *panic_notifier_list;
-
-static int __init panic_setup(char *str)
-{
- panic_timeout = simple_strtoul(str, NULL, 0);
- return 1;
-}
-
-__setup("panic=", panic_setup);
-
-/**
- * panic - halt the system
- * @fmt: The text string to print
- *
- * Display a message, then perform cleanups. Functions in the panic
- * notifier list are called after the filesystem cache is flushed (when possible).
- *
- * This function never returns.
- */
-
-NORET_TYPE void panic(const char * fmt, ...)
-{
- static char buf[1024];
- va_list args;
-#if defined(CONFIG_ARCH_S390)
- unsigned long caller = (unsigned long) __builtin_return_address(0);
-#endif
-
- bust_spinlocks(1);
- va_start(args, fmt);
- vsprintf(buf, fmt, args);
- va_end(args);
- printk(KERN_EMERG "Kernel panic: %s\n",buf);
- if (in_interrupt())
- printk(KERN_EMERG "In interrupt handler - not syncing\n");
- else if (!current->pid)
- printk(KERN_EMERG "In idle task - not syncing\n");
- else
- sys_sync();
- bust_spinlocks(0);
-
-#ifdef CONFIG_SMP
- smp_send_stop();
-#endif
-
- notifier_call_chain(&panic_notifier_list, 0, NULL);
-
- if (panic_timeout > 0)
- {
- /*
- * Delay timeout seconds before rebooting the machine.
- * We can't use the "normal" timers since we just panicked..
- */
- printk(KERN_EMERG "Rebooting in %d seconds..",panic_timeout);
- mdelay(panic_timeout*1000);
- /*
- * Should we run the reboot notifier. For the moment Im
- * choosing not too. It might crash, be corrupt or do
- * more harm than good for other reasons.
- */
- machine_restart(NULL);
- }
-#ifdef __sparc__
- {
- extern int stop_a_enabled;
- /* Make sure the user can actually press L1-A */
- stop_a_enabled = 1;
- printk("Press L1-A to return to the boot prom\n");
- }
-#endif
-#if defined(CONFIG_ARCH_S390)
- disabled_wait(caller);
-#endif
- sti();
- for(;;) {
-#if defined(CONFIG_X86) && defined(CONFIG_VT)
- extern void panic_blink(void);
- panic_blink();
-#endif
- CHECK_EMERGENCY_SYNC
-#if defined(CONFIG_XENO)
- HYPERVISOR_exit();
-#endif
- }
-}
-
-/**
- * print_tainted - return a string to represent the kernel taint state.
- *
- * The string is overwritten by the next call to print_taint().
- */
-
-const char *print_tainted()
-{
- static char buf[20];
- if (tainted) {
- snprintf(buf, sizeof(buf), "Tainted: %c%c",
- tainted & 1 ? 'P' : 'G',
- tainted & 2 ? 'F' : ' ');
- }
- else
- snprintf(buf, sizeof(buf), "Not tainted");
- return(buf);
-}
-
-int tainted = 0;
-
-/*
- * A BUG() call in an inline function in a header should be avoided,
- * because it can seriously bloat the kernel. So here we have
- * helper functions.
- * We lose the BUG()-time file-and-line info this way, but it's
- * usually not very useful from an inline anyway. The backtrace
- * tells us what we want to know.
- */
-
-void __out_of_line_bug(int line)
-{
- printk("kernel BUG in header file at line %d\n", line);
-
- BUG();
-
- /* Satisfy __attribute__((noreturn)) */
- for ( ; ; )
- ;
-}
+++ /dev/null
-#!/bin/sh
-
-# mkbuildtree <build tree>
-#
-# Creates symbolic links in <build tree> for the sparse tree
-# in the current directory.
-
-# Script to determine the relative path between two directories.
-# Copyright (c) D. J. Hawkey Jr. 2002
-# Fixed for Xen project by K. Fraser in 2003.
-abs_to_rel ()
-{
- local CWD SRCPATH
-
- if [ "$1" != "/" -a "${1##*[^/]}" = "/" ]; then
- SRCPATH=${1%?}
- else
- SRCPATH=$1
- fi
- if [ "$2" != "/" -a "${2##*[^/]}" = "/" ]; then
- DESTPATH=${2%?}
- else
- DESTPATH=$2
- fi
-
- CWD=$PWD
- [ "${1%%[^/]*}" != "/" ] && cd $1 && SRCPATH=$PWD
- [ "${2%%[^/]*}" != "/" ] && cd $2 && DESTPATH=$PWD
- [ "$CWD" != "$PWD" ] && cd $CWD
-
- BASEPATH=$SRCPATH
-
- [ "$SRCPATH" = "$DESTPATH" ] && DESTPATH="." && return
- [ "$SRCPATH" = "/" ] && DESTPATH=${DESTPATH#?} && return
-
- while [ "$BASEPATH/" != "${DESTPATH%${DESTPATH#$BASEPATH/}}" ]; do
- BASEPATH=${BASEPATH%/*}
- done
-
- SRCPATH=${SRCPATH#$BASEPATH}
- DESTPATH=${DESTPATH#$BASEPATH}
- DESTPATH=${DESTPATH#?}
- while [ -n "$SRCPATH" ]; do
- SRCPATH=${SRCPATH%/*}
- DESTPATH="../$DESTPATH"
- done
-
- [ -z "$BASEPATH" ] && BASEPATH="/"
- [ "${DESTPATH##*[^/]}" = "/" ] && DESTPATH=${DESTPATH%?}
-}
-
-
-[ "$1" == "" ] && { echo "Syntax: $0 <linux tree to xenify>"; exit 1; }
-
-# Get absolute path to the destination directory
-pushd . >/dev/null
-cd ${1}
-AD=`pwd`
-popd >/dev/null
-
-# Get absolute path to the source directory
-AS=`pwd`
-
-# Get path to source, relative to destination
-abs_to_rel ${AD} ${AS}
-RS=$DESTPATH
-
-# Remove old copies of files and directories at the destination
-for i in `find . -type f -o -type l` ; do rm -f ${AD}/${i#./} ; done
-
-# We now work from the destination directory
-cd ${AD}
-
-# Create symlinks of files and directories which exist in the sparse source
-${AS}/lndir-rel -silent ${RS}
-rm -f mkbuildtree lndir-rel
-
-## There are a whole bunch of special symlinks, mostly for files
-## which are identical in the i386 and xeno-i386 architecture-dependent
-## subdirectories.
-
-# This first symlink is special: it links to shared files in Xen's source tree
-rm -rf ${AD}/include/asm-xeno/hypervisor-ifs
-mkdir ${AD}/include/asm-xeno/hypervisor-ifs
-cd ${AD}/include/asm-xeno/hypervisor-ifs
-${AS}/lndir-rel -silent ../../../${RS}/../xen/include/hypervisor-ifs
-
-# The remainder are the i386 -> xeno-i386 links
-cd ..
-ln -sf ../asm-i386/a.out.h
-ln -sf ../asm-i386/apicdef.h
-ln -sf ../asm-i386/apic.h
-ln -sf ../asm-i386/atomic.h
-ln -sf ../asm-i386/bitops.h
-ln -sf ../asm-i386/boot.h
-ln -sf ../asm-i386/byteorder.h
-ln -sf ../asm-i386/cache.h
-ln -sf ../asm-i386/checksum.h
-ln -sf ../asm-i386/cpufeature.h
-ln -sf ../asm-i386/current.h
-ln -sf ../asm-i386/debugreg.h
-ln -sf ../asm-i386/delay.h
-ln -sf ../asm-i386/div64.h
-ln -sf ../asm-i386/dma.h
-ln -sf ../asm-i386/elf.h
-ln -sf ../asm-i386/errno.h
-ln -sf ../asm-i386/fcntl.h
-ln -sf ../asm-i386/floppy.h
-ln -sf ../asm-i386/hardirq.h
-ln -sf ../asm-i386/hdreg.h
-ln -sf ../asm-i386/i387.h
-ln -sf ../asm-i386/ide.h
-ln -sf ../asm-i386/init.h
-ln -sf ../asm-i386/io_apic.h
-ln -sf ../asm-i386/ioctl.h
-ln -sf ../asm-i386/ioctls.h
-ln -sf ../asm-i386/ipcbuf.h
-ln -sf ../asm-i386/ipc.h
-ln -sf ../asm-i386/kmap_types.h
-ln -sf ../asm-i386/ldt.h
-ln -sf ../asm-i386/linux_logo.h
-ln -sf ../asm-i386/locks.h
-ln -sf ../asm-i386/math_emu.h
-ln -sf ../asm-i386/mc146818rtc.h
-ln -sf ../asm-i386/mca_dma.h
-ln -sf ../asm-i386/mman.h
-ln -sf ../asm-i386/mmx.h
-ln -sf ../asm-i386/module.h
-ln -sf ../asm-i386/mpspec.h
-ln -sf ../asm-i386/msgbuf.h
-ln -sf ../asm-i386/msr.h
-ln -sf ../asm-i386/mtrr.h
-ln -sf ../asm-i386/namei.h
-ln -sf ../asm-i386/param.h
-ln -sf ../asm-i386/parport.h
-ln -sf ../asm-i386/pgtable-3level.h
-ln -sf ../asm-i386/poll.h
-ln -sf ../asm-i386/posix_types.h
-ln -sf ../asm-i386/resource.h
-ln -sf ../asm-i386/rwlock.h
-ln -sf ../asm-i386/rwsem.h
-ln -sf ../asm-i386/scatterlist.h
-ln -sf ../asm-i386/semaphore.h
-ln -sf ../asm-i386/sembuf.h
-ln -sf ../asm-i386/serial.h
-ln -sf ../asm-i386/setup.h
-ln -sf ../asm-i386/shmbuf.h
-ln -sf ../asm-i386/shmparam.h
-ln -sf ../asm-i386/sigcontext.h
-ln -sf ../asm-i386/siginfo.h
-ln -sf ../asm-i386/signal.h
-ln -sf ../asm-i386/smplock.h
-ln -sf ../asm-i386/socket.h
-ln -sf ../asm-i386/sockios.h
-ln -sf ../asm-i386/softirq.h
-ln -sf ../asm-i386/spinlock.h
-ln -sf ../asm-i386/statfs.h
-ln -sf ../asm-i386/stat.h
-ln -sf ../asm-i386/string-486.h
-ln -sf ../asm-i386/string.h
-ln -sf ../asm-i386/termbits.h
-ln -sf ../asm-i386/termios.h
-ln -sf ../asm-i386/timex.h
-ln -sf ../asm-i386/tlb.h
-ln -sf ../asm-i386/types.h
-ln -sf ../asm-i386/uaccess.h
-ln -sf ../asm-i386/ucontext.h
-ln -sf ../asm-i386/unaligned.h
-ln -sf ../asm-i386/unistd.h
-ln -sf ../asm-i386/user.h
-ln -sf ../asm-i386/vga.h
-ln -sf ../asm-i386/xor.h
-
-cd ../../arch/xeno/kernel
-ln -sf ../../i386/kernel/i387.c
-ln -sf ../../i386/kernel/init_task.c
-ln -sf ../../i386/kernel/ptrace.c
-ln -sf ../../i386/kernel/semaphore.c
-ln -sf ../../i386/kernel/sys_i386.c
-cd ../lib
-ln -sf ../../i386/lib/checksum.S
-ln -sf ../../i386/lib/dec_and_lock.c
-ln -sf ../../i386/lib/getuser.S
-ln -sf ../../i386/lib/iodebug.c
-ln -sf ../../i386/lib/memcpy.c
-ln -sf ../../i386/lib/mmx.c
-ln -sf ../../i386/lib/old-checksum.c
-ln -sf ../../i386/lib/strstr.c
-ln -sf ../../i386/lib/usercopy.c
-cd ../mm
-ln -sf ../../i386/mm/extable.c
-ln -sf ../../i386/mm/pageattr.c
+++ /dev/null
-/*
- * linux/mm/memory.c
- *
- * Copyright (C) 1991, 1992, 1993, 1994 Linus Torvalds
- */
-
-/*
- * demand-loading started 01.12.91 - seems it is high on the list of
- * things wanted, and it should be easy to implement. - Linus
- */
-
-/*
- * Ok, demand-loading was easy, shared pages a little bit tricker. Shared
- * pages started 02.12.91, seems to work. - Linus.
- *
- * Tested sharing by executing about 30 /bin/sh: under the old kernel it
- * would have taken more than the 6M I have free, but it worked well as
- * far as I could see.
- *
- * Also corrected some "invalidate()"s - I wasn't doing enough of them.
- */
-
-/*
- * Real VM (paging to/from disk) started 18.12.91. Much more work and
- * thought has to go into this. Oh, well..
- * 19.12.91 - works, somewhat. Sometimes I get faults, don't know why.
- * Found it. Everything seems to work now.
- * 20.12.91 - Ok, making the swap-device changeable like the root.
- */
-
-/*
- * 05.04.94 - Multi-page memory management added for v1.1.
- * Idea by Alex Bligh (alex@cconcepts.co.uk)
- *
- * 16.07.99 - Support of BIGMEM added by Gerhard Wichert, Siemens AG
- * (Gerhard.Wichert@pdb.siemens.de)
- */
-
-#include <linux/mm.h>
-#include <linux/mman.h>
-#include <linux/swap.h>
-#include <linux/smp_lock.h>
-#include <linux/swapctl.h>
-#include <linux/iobuf.h>
-#include <linux/highmem.h>
-#include <linux/pagemap.h>
-#include <linux/module.h>
-
-#include <asm/pgalloc.h>
-#include <asm/uaccess.h>
-#include <asm/tlb.h>
-
-unsigned long max_mapnr;
-unsigned long num_physpages;
-unsigned long num_mappedpages;
-void * high_memory;
-struct page *highmem_start_page;
-
-/*
- * We special-case the C-O-W ZERO_PAGE, because it's such
- * a common occurrence (no need to read the page to know
- * that it's zero - better for the cache and memory subsystem).
- */
-static inline void copy_cow_page(struct page * from, struct page * to, unsigned long address)
-{
- if (from == ZERO_PAGE(address)) {
- clear_user_highpage(to, address);
- return;
- }
- copy_user_highpage(to, from, address);
-}
-
-mem_map_t * mem_map;
-
-/*
- * Called by TLB shootdown
- */
-void __free_pte(pte_t pte)
-{
- struct page *page = pte_page(pte);
- if ((!VALID_PAGE(page)) || PageReserved(page))
- return;
- if (pte_dirty(pte))
- set_page_dirty(page);
- free_page_and_swap_cache(page);
-}
-
-
-/*
- * Note: this doesn't free the actual pages themselves. That
- * has been handled earlier when unmapping all the memory regions.
- */
-static inline void free_one_pmd(pmd_t * dir)
-{
- pte_t * pte;
-
- if (pmd_none(*dir))
- return;
- if (pmd_bad(*dir)) {
- pmd_ERROR(*dir);
- pmd_clear(dir);
- return;
- }
- pte = pte_offset(dir, 0);
- pmd_clear(dir);
- pte_free(pte);
-}
-
-static inline void free_one_pgd(pgd_t * dir)
-{
- int j;
- pmd_t * pmd;
-
- if (pgd_none(*dir))
- return;
- if (pgd_bad(*dir)) {
- pgd_ERROR(*dir);
- pgd_clear(dir);
- return;
- }
- pmd = pmd_offset(dir, 0);
- pgd_clear(dir);
- for (j = 0; j < PTRS_PER_PMD ; j++) {
- prefetchw(pmd+j+(PREFETCH_STRIDE/16));
- free_one_pmd(pmd+j);
- }
- pmd_free(pmd);
-}
-
-/* Low and high watermarks for page table cache.
- The system should try to have pgt_water[0] <= cache elements <= pgt_water[1]
- */
-int pgt_cache_water[2] = { 25, 50 };
-
-/* Returns the number of pages freed */
-int check_pgt_cache(void)
-{
- return do_check_pgt_cache(pgt_cache_water[0], pgt_cache_water[1]);
-}
-
-
-/*
- * This function clears all user-level page tables of a process - this
- * is needed by execve(), so that old pages aren't in the way.
- */
-void clear_page_tables(struct mm_struct *mm, unsigned long first, int nr)
-{
- pgd_t * page_dir = mm->pgd;
-
- spin_lock(&mm->page_table_lock);
- page_dir += first;
- do {
- free_one_pgd(page_dir);
- page_dir++;
- } while (--nr);
- XENO_flush_page_update_queue();
- spin_unlock(&mm->page_table_lock);
-
- /* keep the page table cache within bounds */
- check_pgt_cache();
-}
-
-#define PTE_TABLE_MASK ((PTRS_PER_PTE-1) * sizeof(pte_t))
-#define PMD_TABLE_MASK ((PTRS_PER_PMD-1) * sizeof(pmd_t))
-
-/*
- * copy one vm_area from one task to the other. Assumes the page tables
- * already present in the new task to be cleared in the whole range
- * covered by this vma.
- *
- * 08Jan98 Merged into one routine from several inline routines to reduce
- * variable count and make things faster. -jj
- *
- * dst->page_table_lock is held on entry and exit,
- * but may be dropped within pmd_alloc() and pte_alloc().
- */
-int copy_page_range(struct mm_struct *dst, struct mm_struct *src,
- struct vm_area_struct *vma)
-{
- pgd_t * src_pgd, * dst_pgd;
- unsigned long address = vma->vm_start;
- unsigned long end = vma->vm_end;
- unsigned long cow = (vma->vm_flags & (VM_SHARED | VM_MAYWRITE)) == VM_MAYWRITE;
-
- src_pgd = pgd_offset(src, address)-1;
- dst_pgd = pgd_offset(dst, address)-1;
-
- for (;;) {
- pmd_t * src_pmd, * dst_pmd;
-
- src_pgd++; dst_pgd++;
-
- /* copy_pmd_range */
-
- if (pgd_none(*src_pgd))
- goto skip_copy_pmd_range;
- if (pgd_bad(*src_pgd)) {
- pgd_ERROR(*src_pgd);
- pgd_clear(src_pgd);
-skip_copy_pmd_range: address = (address + PGDIR_SIZE) & PGDIR_MASK;
- if (!address || (address >= end))
- goto out;
- continue;
- }
-
- src_pmd = pmd_offset(src_pgd, address);
- dst_pmd = pmd_alloc(dst, dst_pgd, address);
- if (!dst_pmd)
- goto nomem;
-
- do {
- pte_t * src_pte, * dst_pte;
-
- /* copy_pte_range */
-
- if (pmd_none(*src_pmd))
- goto skip_copy_pte_range;
- if (pmd_bad(*src_pmd)) {
- pmd_ERROR(*src_pmd);
- pmd_clear(src_pmd);
-skip_copy_pte_range: address = (address + PMD_SIZE) & PMD_MASK;
- if (address >= end)
- goto out;
- goto cont_copy_pmd_range;
- }
-
- src_pte = pte_offset(src_pmd, address);
- dst_pte = pte_alloc(dst, dst_pmd, address);
- if (!dst_pte)
- goto nomem;
-
- spin_lock(&src->page_table_lock);
- do {
- pte_t pte = *src_pte;
- struct page *ptepage;
-
- /* copy_one_pte */
-
- if (pte_none(pte))
- goto cont_copy_pte_range_noset;
- if (!pte_present(pte)) {
- swap_duplicate(pte_to_swp_entry(pte));
- goto cont_copy_pte_range;
- }
- ptepage = pte_page(pte);
- if ((!VALID_PAGE(ptepage)) ||
- PageReserved(ptepage))
- goto cont_copy_pte_range;
-
- /* If it's a COW mapping, write protect it both in the parent and the child */
- if (cow && pte_write(pte)) {
- /* XENO modification: modified ordering here to avoid RaW hazard. */
- pte = *src_pte;
- pte = pte_wrprotect(pte);
- ptep_set_wrprotect(src_pte);
- }
-
- /* If it's a shared mapping, mark it clean in the child */
- if (vma->vm_flags & VM_SHARED)
- pte = pte_mkclean(pte);
- pte = pte_mkold(pte);
- get_page(ptepage);
- dst->rss++;
-
-cont_copy_pte_range: set_pte(dst_pte, pte);
-cont_copy_pte_range_noset: address += PAGE_SIZE;
- if (address >= end)
- goto out_unlock;
- src_pte++;
- dst_pte++;
- } while ((unsigned long)src_pte & PTE_TABLE_MASK);
- spin_unlock(&src->page_table_lock);
-
-cont_copy_pmd_range: src_pmd++;
- dst_pmd++;
- } while ((unsigned long)src_pmd & PMD_TABLE_MASK);
- }
-out_unlock:
- spin_unlock(&src->page_table_lock);
-out:
- return 0;
-nomem:
- return -ENOMEM;
-}
-
-/*
- * Return indicates whether a page was freed so caller can adjust rss
- */
-static inline void forget_pte(pte_t page)
-{
- if (!pte_none(page)) {
- printk("forget_pte: old mapping existed!\n");
- BUG();
- }
-}
-
-static inline int zap_pte_range(mmu_gather_t *tlb, pmd_t * pmd, unsigned long address, unsigned long size)
-{
- unsigned long offset;
- pte_t * ptep;
- int freed = 0;
-
- if (pmd_none(*pmd))
- return 0;
- if (pmd_bad(*pmd)) {
- pmd_ERROR(*pmd);
- pmd_clear(pmd);
- return 0;
- }
- ptep = pte_offset(pmd, address);
- offset = address & ~PMD_MASK;
- if (offset + size > PMD_SIZE)
- size = PMD_SIZE - offset;
- size &= PAGE_MASK;
- for (offset=0; offset < size; ptep++, offset += PAGE_SIZE) {
- pte_t pte = *ptep;
- if (pte_none(pte))
- continue;
- if (pte_present(pte)) {
- struct page *page = pte_page(pte);
- if (VALID_PAGE(page) && !PageReserved(page))
- freed ++;
- /* This will eventually call __free_pte on the pte. */
- tlb_remove_page(tlb, ptep, address + offset);
- } else {
- free_swap_and_cache(pte_to_swp_entry(pte));
- pte_clear(ptep);
- }
- }
-
- return freed;
-}
-
-static inline int zap_pmd_range(mmu_gather_t *tlb, pgd_t * dir, unsigned long address, unsigned long size)
-{
- pmd_t * pmd;
- unsigned long end;
- int freed;
-
- if (pgd_none(*dir))
- return 0;
- if (pgd_bad(*dir)) {
- pgd_ERROR(*dir);
- pgd_clear(dir);
- return 0;
- }
- pmd = pmd_offset(dir, address);
- end = address + size;
- if (end > ((address + PGDIR_SIZE) & PGDIR_MASK))
- end = ((address + PGDIR_SIZE) & PGDIR_MASK);
- freed = 0;
- do {
- freed += zap_pte_range(tlb, pmd, address, end - address);
- address = (address + PMD_SIZE) & PMD_MASK;
- pmd++;
- } while (address < end);
- return freed;
-}
-
-/*
- * remove user pages in a given range.
- */
-void zap_page_range(struct mm_struct *mm, unsigned long address, unsigned long size)
-{
- mmu_gather_t *tlb;
- pgd_t * dir;
- unsigned long start = address, end = address + size;
- int freed = 0;
-
- dir = pgd_offset(mm, address);
-
- /*
- * This is a long-lived spinlock. That's fine.
- * There's no contention, because the page table
- * lock only protects against kswapd anyway, and
- * even if kswapd happened to be looking at this
- * process we _want_ it to get stuck.
- */
- if (address >= end)
- BUG();
- spin_lock(&mm->page_table_lock);
- flush_cache_range(mm, address, end);
- tlb = tlb_gather_mmu(mm);
-
- do {
- freed += zap_pmd_range(tlb, dir, address, end - address);
- address = (address + PGDIR_SIZE) & PGDIR_MASK;
- dir++;
- } while (address && (address < end));
-
- /* this will flush any remaining tlb entries */
- tlb_finish_mmu(tlb, start, end);
-
- /*
- * Update rss for the mm_struct (not necessarily current->mm)
- * Notice that rss is an unsigned long.
- */
- if (mm->rss > freed)
- mm->rss -= freed;
- else
- mm->rss = 0;
- spin_unlock(&mm->page_table_lock);
-}
-
-/*
- * Do a quick page-table lookup for a single page.
- */
-static struct page * follow_page(struct mm_struct *mm, unsigned long address, int write)
-{
- pgd_t *pgd;
- pmd_t *pmd;
- pte_t *ptep, pte;
-
- pgd = pgd_offset(mm, address);
- if (pgd_none(*pgd) || pgd_bad(*pgd))
- goto out;
-
- pmd = pmd_offset(pgd, address);
- if (pmd_none(*pmd) || pmd_bad(*pmd))
- goto out;
-
- ptep = pte_offset(pmd, address);
- if (!ptep)
- goto out;
-
- pte = *ptep;
- if (pte_present(pte)) {
- if (!write ||
- (pte_write(pte) && pte_dirty(pte)))
- return pte_page(pte);
- }
-
-out:
- return 0;
-}
-
-/*
- * Given a physical address, is there a useful struct page pointing to
- * it? This may become more complex in the future if we start dealing
- * with IO-aperture pages in kiobufs.
- */
-
-static inline struct page * get_page_map(struct page *page)
-{
- if (!VALID_PAGE(page))
- return 0;
- return page;
-}
-
-/*
- * Please read Documentation/cachetlb.txt before using this function,
- * accessing foreign memory spaces can cause cache coherency problems.
- *
- * Accessing a VM_IO area is even more dangerous, therefore the function
- * fails if pages is != NULL and a VM_IO area is found.
- */
-int get_user_pages(struct task_struct *tsk, struct mm_struct *mm, unsigned long start,
- int len, int write, int force, struct page **pages, struct vm_area_struct **vmas)
-{
- int i;
- unsigned int flags;
-
- /*
- * Require read or write permissions.
- * If 'force' is set, we only require the "MAY" flags.
- */
- flags = write ? (VM_WRITE | VM_MAYWRITE) : (VM_READ | VM_MAYREAD);
- flags &= force ? (VM_MAYREAD | VM_MAYWRITE) : (VM_READ | VM_WRITE);
- i = 0;
-
- do {
- struct vm_area_struct * vma;
-
- vma = find_extend_vma(mm, start);
-
- if ( !vma || (pages && vma->vm_flags & VM_IO) || !(flags & vma->vm_flags) )
- return i ? : -EFAULT;
-
- spin_lock(&mm->page_table_lock);
- do {
- struct page *map;
- while (!(map = follow_page(mm, start, write))) {
- spin_unlock(&mm->page_table_lock);
- switch (handle_mm_fault(mm, vma, start, write)) {
- case 1:
- tsk->min_flt++;
- break;
- case 2:
- tsk->maj_flt++;
- break;
- case 0:
- if (i) return i;
- return -EFAULT;
- default:
- if (i) return i;
- return -ENOMEM;
- }
- spin_lock(&mm->page_table_lock);
- }
- if (pages) {
- pages[i] = get_page_map(map);
- /* FIXME: call the correct function,
- * depending on the type of the found page
- */
- if (!pages[i])
- goto bad_page;
- page_cache_get(pages[i]);
- }
- if (vmas)
- vmas[i] = vma;
- i++;
- start += PAGE_SIZE;
- len--;
- } while(len && start < vma->vm_end);
- spin_unlock(&mm->page_table_lock);
- } while(len);
-out:
- return i;
-
- /*
- * We found an invalid page in the VMA. Release all we have
- * so far and fail.
- */
-bad_page:
- spin_unlock(&mm->page_table_lock);
- while (i--)
- page_cache_release(pages[i]);
- i = -EFAULT;
- goto out;
-}
-
-EXPORT_SYMBOL(get_user_pages);
-
-/*
- * Force in an entire range of pages from the current process's user VA,
- * and pin them in physical memory.
- */
-#define dprintk(x...)
-
-int map_user_kiobuf(int rw, struct kiobuf *iobuf, unsigned long va, size_t len)
-{
- int pgcount, err;
- struct mm_struct * mm;
-
- /* Make sure the iobuf is not already mapped somewhere. */
- if (iobuf->nr_pages)
- return -EINVAL;
-
- mm = current->mm;
- dprintk ("map_user_kiobuf: begin\n");
-
- pgcount = (va + len + PAGE_SIZE - 1)/PAGE_SIZE - va/PAGE_SIZE;
- /* mapping 0 bytes is not permitted */
- if (!pgcount) BUG();
- err = expand_kiobuf(iobuf, pgcount);
- if (err)
- return err;
-
- iobuf->locked = 0;
- iobuf->offset = va & (PAGE_SIZE-1);
- iobuf->length = len;
-
- /* Try to fault in all of the necessary pages */
- down_read(&mm->mmap_sem);
- /* rw==READ means read from disk, write into memory area */
- err = get_user_pages(current, mm, va, pgcount,
- (rw==READ), 0, iobuf->maplist, NULL);
- up_read(&mm->mmap_sem);
- if (err < 0) {
- unmap_kiobuf(iobuf);
- dprintk ("map_user_kiobuf: end %d\n", err);
- return err;
- }
- iobuf->nr_pages = err;
- while (pgcount--) {
- /* FIXME: flush superflous for rw==READ,
- * probably wrong function for rw==WRITE
- */
- flush_dcache_page(iobuf->maplist[pgcount]);
- }
- dprintk ("map_user_kiobuf: end OK\n");
- return 0;
-}
-
-/*
- * Mark all of the pages in a kiobuf as dirty
- *
- * We need to be able to deal with short reads from disk: if an IO error
- * occurs, the number of bytes read into memory may be less than the
- * size of the kiobuf, so we have to stop marking pages dirty once the
- * requested byte count has been reached.
- *
- * Must be called from process context - set_page_dirty() takes VFS locks.
- */
-
-void mark_dirty_kiobuf(struct kiobuf *iobuf, int bytes)
-{
- int index, offset, remaining;
- struct page *page;
-
- index = iobuf->offset >> PAGE_SHIFT;
- offset = iobuf->offset & ~PAGE_MASK;
- remaining = bytes;
- if (remaining > iobuf->length)
- remaining = iobuf->length;
-
- while (remaining > 0 && index < iobuf->nr_pages) {
- page = iobuf->maplist[index];
-
- if (!PageReserved(page))
- set_page_dirty(page);
-
- remaining -= (PAGE_SIZE - offset);
- offset = 0;
- index++;
- }
-}
-
-/*
- * Unmap all of the pages referenced by a kiobuf. We release the pages,
- * and unlock them if they were locked.
- */
-
-void unmap_kiobuf (struct kiobuf *iobuf)
-{
- int i;
- struct page *map;
-
- for (i = 0; i < iobuf->nr_pages; i++) {
- map = iobuf->maplist[i];
- if (map) {
- if (iobuf->locked)
- UnlockPage(map);
- /* FIXME: cache flush missing for rw==READ
- * FIXME: call the correct reference counting function
- */
- page_cache_release(map);
- }
- }
-
- iobuf->nr_pages = 0;
- iobuf->locked = 0;
-}
-
-
-/*
- * Lock down all of the pages of a kiovec for IO.
- *
- * If any page is mapped twice in the kiovec, we return the error -EINVAL.
- *
- * The optional wait parameter causes the lock call to block until all
- * pages can be locked if set. If wait==0, the lock operation is
- * aborted if any locked pages are found and -EAGAIN is returned.
- */
-
-int lock_kiovec(int nr, struct kiobuf *iovec[], int wait)
-{
- struct kiobuf *iobuf;
- int i, j;
- struct page *page, **ppage;
- int doublepage = 0;
- int repeat = 0;
-
- repeat:
-
- for (i = 0; i < nr; i++) {
- iobuf = iovec[i];
-
- if (iobuf->locked)
- continue;
-
- ppage = iobuf->maplist;
- for (j = 0; j < iobuf->nr_pages; ppage++, j++) {
- page = *ppage;
- if (!page)
- continue;
-
- if (TryLockPage(page)) {
- while (j--) {
- struct page *tmp = *--ppage;
- if (tmp)
- UnlockPage(tmp);
- }
- goto retry;
- }
- }
- iobuf->locked = 1;
- }
-
- return 0;
-
- retry:
-
- /*
- * We couldn't lock one of the pages. Undo the locking so far,
- * wait on the page we got to, and try again.
- */
-
- unlock_kiovec(nr, iovec);
- if (!wait)
- return -EAGAIN;
-
- /*
- * Did the release also unlock the page we got stuck on?
- */
- if (!PageLocked(page)) {
- /*
- * If so, we may well have the page mapped twice
- * in the IO address range. Bad news. Of
- * course, it _might_ just be a coincidence,
- * but if it happens more than once, chances
- * are we have a double-mapped page.
- */
- if (++doublepage >= 3)
- return -EINVAL;
-
- /* Try again... */
- wait_on_page(page);
- }
-
- if (++repeat < 16)
- goto repeat;
- return -EAGAIN;
-}
-
-/*
- * Unlock all of the pages of a kiovec after IO.
- */
-
-int unlock_kiovec(int nr, struct kiobuf *iovec[])
-{
- struct kiobuf *iobuf;
- int i, j;
- struct page *page, **ppage;
-
- for (i = 0; i < nr; i++) {
- iobuf = iovec[i];
-
- if (!iobuf->locked)
- continue;
- iobuf->locked = 0;
-
- ppage = iobuf->maplist;
- for (j = 0; j < iobuf->nr_pages; ppage++, j++) {
- page = *ppage;
- if (!page)
- continue;
- UnlockPage(page);
- }
- }
- return 0;
-}
-
-static inline void zeromap_pte_range(pte_t * pte, unsigned long address,
- unsigned long size, pgprot_t prot)
-{
- unsigned long end;
-
- address &= ~PMD_MASK;
- end = address + size;
- if (end > PMD_SIZE)
- end = PMD_SIZE;
- do {
- pte_t zero_pte = pte_wrprotect(mk_pte(ZERO_PAGE(address), prot));
- pte_t oldpage = ptep_get_and_clear(pte);
- set_pte(pte, zero_pte);
- forget_pte(oldpage);
- address += PAGE_SIZE;
- pte++;
- } while (address && (address < end));
-}
-
-static inline int zeromap_pmd_range(struct mm_struct *mm, pmd_t * pmd, unsigned long address,
- unsigned long size, pgprot_t prot)
-{
- unsigned long end;
-
- address &= ~PGDIR_MASK;
- end = address + size;
- if (end > PGDIR_SIZE)
- end = PGDIR_SIZE;
- do {
- pte_t * pte = pte_alloc(mm, pmd, address);
- if (!pte)
- return -ENOMEM;
- zeromap_pte_range(pte, address, end - address, prot);
- address = (address + PMD_SIZE) & PMD_MASK;
- pmd++;
- } while (address && (address < end));
- return 0;
-}
-
-int zeromap_page_range(unsigned long address, unsigned long size, pgprot_t prot)
-{
- int error = 0;
- pgd_t * dir;
- unsigned long beg = address;
- unsigned long end = address + size;
- struct mm_struct *mm = current->mm;
-
- dir = pgd_offset(mm, address);
- flush_cache_range(mm, beg, end);
- if (address >= end)
- BUG();
-
- spin_lock(&mm->page_table_lock);
- do {
- pmd_t *pmd = pmd_alloc(mm, dir, address);
- error = -ENOMEM;
- if (!pmd)
- break;
- error = zeromap_pmd_range(mm, pmd, address, end - address, prot);
- if (error)
- break;
- address = (address + PGDIR_SIZE) & PGDIR_MASK;
- dir++;
- } while (address && (address < end));
- spin_unlock(&mm->page_table_lock);
- flush_tlb_range(mm, beg, end);
- return error;
-}
-
-/*
- * maps a range of physical memory into the requested pages. the old
- * mappings are removed. any references to nonexistent pages results
- * in null mappings (currently treated as "copy-on-access")
- */
-static inline void remap_pte_range(pte_t * pte, unsigned long address, unsigned long size,
- unsigned long phys_addr, pgprot_t prot)
-{
- unsigned long end;
-
- address &= ~PMD_MASK;
- end = address + size;
- if (end > PMD_SIZE)
- end = PMD_SIZE;
- do {
- struct page *page;
- pte_t oldpage;
- oldpage = ptep_get_and_clear(pte);
-
- page = virt_to_page(__va(phys_addr));
- if ((!VALID_PAGE(page)) || PageReserved(page))
- set_pte(pte, mk_pte_phys(phys_addr, prot));
- forget_pte(oldpage);
- address += PAGE_SIZE;
- phys_addr += PAGE_SIZE;
- pte++;
- } while (address && (address < end));
-}
-
-static inline int remap_pmd_range(struct mm_struct *mm, pmd_t * pmd, unsigned long address, unsigned long size,
- unsigned long phys_addr, pgprot_t prot)
-{
- unsigned long end;
-
- address &= ~PGDIR_MASK;
- end = address + size;
- if (end > PGDIR_SIZE)
- end = PGDIR_SIZE;
- phys_addr -= address;
- do {
- pte_t * pte = pte_alloc(mm, pmd, address);
- if (!pte)
- return -ENOMEM;
- remap_pte_range(pte, address, end - address, address + phys_addr, prot);
- address = (address + PMD_SIZE) & PMD_MASK;
- pmd++;
- } while (address && (address < end));
- return 0;
-}
-
-/* Note: this is only safe if the mm semaphore is held when called. */
-int remap_page_range(unsigned long from, unsigned long phys_addr, unsigned long size, pgprot_t prot)
-{
- int error = 0;
- pgd_t * dir;
- unsigned long beg = from;
- unsigned long end = from + size;
- struct mm_struct *mm = current->mm;
-
- phys_addr -= from;
- dir = pgd_offset(mm, from);
- flush_cache_range(mm, beg, end);
- if (from >= end)
- BUG();
-
- spin_lock(&mm->page_table_lock);
- do {
- pmd_t *pmd = pmd_alloc(mm, dir, from);
- error = -ENOMEM;
- if (!pmd)
- break;
- error = remap_pmd_range(mm, pmd, from, end - from, phys_addr + from, prot);
- if (error)
- break;
- from = (from + PGDIR_SIZE) & PGDIR_MASK;
- dir++;
- } while (from && (from < end));
- spin_unlock(&mm->page_table_lock);
- flush_tlb_range(mm, beg, end);
- return error;
-}
-
-/*
- * Establish a new mapping:
- * - flush the old one
- * - update the page tables
- * - inform the TLB about the new one
- *
- * We hold the mm semaphore for reading and vma->vm_mm->page_table_lock
- */
-static inline void establish_pte(struct vm_area_struct * vma, unsigned long address, pte_t *page_table, pte_t entry)
-{
- set_pte(page_table, entry);
- flush_tlb_page(vma, address);
- update_mmu_cache(vma, address, entry);
-}
-
-/*
- * We hold the mm semaphore for reading and vma->vm_mm->page_table_lock
- */
-static inline void break_cow(struct vm_area_struct * vma, struct page * new_page, unsigned long address,
- pte_t *page_table)
-{
- flush_page_to_ram(new_page);
- flush_cache_page(vma, address);
- establish_pte(vma, address, page_table, pte_mkwrite(pte_mkdirty(mk_pte(new_page, vma->vm_page_prot))));
-}
-
-/*
- * This routine handles present pages, when users try to write
- * to a shared page. It is done by copying the page to a new address
- * and decrementing the shared-page counter for the old page.
- *
- * Goto-purists beware: the only reason for goto's here is that it results
- * in better assembly code.. The "default" path will see no jumps at all.
- *
- * Note that this routine assumes that the protection checks have been
- * done by the caller (the low-level page fault routine in most cases).
- * Thus we can safely just mark it writable once we've done any necessary
- * COW.
- *
- * We also mark the page dirty at this point even though the page will
- * change only once the write actually happens. This avoids a few races,
- * and potentially makes it more efficient.
- *
- * We hold the mm semaphore and the page_table_lock on entry and exit
- * with the page_table_lock released.
- */
-static int do_wp_page(struct mm_struct *mm, struct vm_area_struct * vma,
- unsigned long address, pte_t *page_table, pte_t pte)
-{
- struct page *old_page, *new_page;
-
- old_page = pte_page(pte);
- if (!VALID_PAGE(old_page))
- goto bad_wp_page;
-
- if (!TryLockPage(old_page)) {
- int reuse = can_share_swap_page(old_page);
- unlock_page(old_page);
- if (reuse) {
- flush_cache_page(vma, address);
- establish_pte(vma, address, page_table, pte_mkyoung(pte_mkdirty(pte_mkwrite(pte))));
- spin_unlock(&mm->page_table_lock);
- return 1; /* Minor fault */
- }
- }
-
- /*
- * Ok, we need to copy. Oh, well..
- */
- page_cache_get(old_page);
- spin_unlock(&mm->page_table_lock);
-
- new_page = alloc_page(GFP_HIGHUSER);
- if (!new_page)
- goto no_mem;
- copy_cow_page(old_page,new_page,address);
-
- /*
- * Re-check the pte - we dropped the lock
- */
- spin_lock(&mm->page_table_lock);
- if (pte_same(*page_table, pte)) {
- if (PageReserved(old_page))
- ++mm->rss;
- break_cow(vma, new_page, address, page_table);
- lru_cache_add(new_page);
-
- /* Free the old page.. */
- new_page = old_page;
- }
- spin_unlock(&mm->page_table_lock);
- page_cache_release(new_page);
- page_cache_release(old_page);
- return 1; /* Minor fault */
-
-bad_wp_page:
- spin_unlock(&mm->page_table_lock);
- printk("do_wp_page: bogus page at address %08lx (page 0x%lx)\n",address,(unsigned long)old_page);
- return -1;
-no_mem:
- page_cache_release(old_page);
- return -1;
-}
-
-static void vmtruncate_list(struct vm_area_struct *mpnt, unsigned long pgoff)
-{
- do {
- struct mm_struct *mm = mpnt->vm_mm;
- unsigned long start = mpnt->vm_start;
- unsigned long end = mpnt->vm_end;
- unsigned long len = end - start;
- unsigned long diff;
-
- /* mapping wholly truncated? */
- if (mpnt->vm_pgoff >= pgoff) {
- zap_page_range(mm, start, len);
- continue;
- }
-
- /* mapping wholly unaffected? */
- len = len >> PAGE_SHIFT;
- diff = pgoff - mpnt->vm_pgoff;
- if (diff >= len)
- continue;
-
- /* Ok, partially affected.. */
- start += diff << PAGE_SHIFT;
- len = (len - diff) << PAGE_SHIFT;
- zap_page_range(mm, start, len);
- } while ((mpnt = mpnt->vm_next_share) != NULL);
-}
-
-/*
- * Handle all mappings that got truncated by a "truncate()"
- * system call.
- *
- * NOTE! We have to be ready to update the memory sharing
- * between the file and the memory map for a potential last
- * incomplete page. Ugly, but necessary.
- */
-int vmtruncate(struct inode * inode, loff_t offset)
-{
- unsigned long pgoff;
- struct address_space *mapping = inode->i_mapping;
- unsigned long limit;
-
- if (inode->i_size < offset)
- goto do_expand;
- inode->i_size = offset;
- spin_lock(&mapping->i_shared_lock);
- if (!mapping->i_mmap && !mapping->i_mmap_shared)
- goto out_unlock;
-
- pgoff = (offset + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
- if (mapping->i_mmap != NULL)
- vmtruncate_list(mapping->i_mmap, pgoff);
- if (mapping->i_mmap_shared != NULL)
- vmtruncate_list(mapping->i_mmap_shared, pgoff);
-
-out_unlock:
- spin_unlock(&mapping->i_shared_lock);
- truncate_inode_pages(mapping, offset);
- goto out_truncate;
-
-do_expand:
- limit = current->rlim[RLIMIT_FSIZE].rlim_cur;
- if (limit != RLIM_INFINITY && offset > limit)
- goto out_sig;
- if (offset > inode->i_sb->s_maxbytes)
- goto out;
- inode->i_size = offset;
-
-out_truncate:
- if (inode->i_op && inode->i_op->truncate) {
- lock_kernel();
- inode->i_op->truncate(inode);
- unlock_kernel();
- }
- return 0;
-out_sig:
- send_sig(SIGXFSZ, current, 0);
-out:
- return -EFBIG;
-}
-
-/*
- * Primitive swap readahead code. We simply read an aligned block of
- * (1 << page_cluster) entries in the swap area. This method is chosen
- * because it doesn't cost us any seek time. We also make sure to queue
- * the 'original' request together with the readahead ones...
- */
-void swapin_readahead(swp_entry_t entry)
-{
- int i, num;
- struct page *new_page;
- unsigned long offset;
-
- /*
- * Get the number of handles we should do readahead io to.
- */
- num = valid_swaphandles(entry, &offset);
- for (i = 0; i < num; offset++, i++) {
- /* Ok, do the async read-ahead now */
- new_page = read_swap_cache_async(SWP_ENTRY(SWP_TYPE(entry), offset));
- if (!new_page)
- break;
- page_cache_release(new_page);
- }
- return;
-}
-
-/*
- * We hold the mm semaphore and the page_table_lock on entry and
- * should release the pagetable lock on exit..
- */
-static int do_swap_page(struct mm_struct * mm,
- struct vm_area_struct * vma, unsigned long address,
- pte_t * page_table, pte_t orig_pte, int write_access)
-{
- struct page *page;
- swp_entry_t entry = pte_to_swp_entry(orig_pte);
- pte_t pte;
- int ret = 1;
-
- spin_unlock(&mm->page_table_lock);
- page = lookup_swap_cache(entry);
- if (!page) {
- swapin_readahead(entry);
- page = read_swap_cache_async(entry);
- if (!page) {
- /*
- * Back out if somebody else faulted in this pte while
- * we released the page table lock.
- */
- int retval;
- spin_lock(&mm->page_table_lock);
- retval = pte_same(*page_table, orig_pte) ? -1 : 1;
- spin_unlock(&mm->page_table_lock);
- return retval;
- }
-
- /* Had to read the page from swap area: Major fault */
- ret = 2;
- }
-
- mark_page_accessed(page);
-
- lock_page(page);
-
- /*
- * Back out if somebody else faulted in this pte while we
- * released the page table lock.
- */
- spin_lock(&mm->page_table_lock);
- if (!pte_same(*page_table, orig_pte)) {
- spin_unlock(&mm->page_table_lock);
- unlock_page(page);
- page_cache_release(page);
- return 1;
- }
-
- /* The page isn't present yet, go ahead with the fault. */
-
- swap_free(entry);
- if (vm_swap_full())
- remove_exclusive_swap_page(page);
-
- mm->rss++;
- pte = mk_pte(page, vma->vm_page_prot);
- if (write_access && can_share_swap_page(page))
- pte = pte_mkdirty(pte_mkwrite(pte));
- unlock_page(page);
-
- flush_page_to_ram(page);
- flush_icache_page(vma, page);
- set_pte(page_table, pte);
-
- /* No need to invalidate - it was non-present before */
- update_mmu_cache(vma, address, pte);
- XENO_flush_page_update_queue();
- spin_unlock(&mm->page_table_lock);
- return ret;
-}
-
-/*
- * We are called with the MM semaphore and page_table_lock
- * spinlock held to protect against concurrent faults in
- * multithreaded programs.
- */
-static int do_anonymous_page(struct mm_struct * mm, struct vm_area_struct * vma, pte_t *page_table, int write_access, unsigned long addr)
-{
- pte_t entry;
-
- /* Read-only mapping of ZERO_PAGE. */
- entry = pte_wrprotect(mk_pte(ZERO_PAGE(addr), vma->vm_page_prot));
-
- /* ..except if it's a write access */
- if (write_access) {
- struct page *page;
-
- /* Allocate our own private page. */
- spin_unlock(&mm->page_table_lock);
-
- page = alloc_page(GFP_HIGHUSER);
- if (!page)
- goto no_mem;
- clear_user_highpage(page, addr);
-
- spin_lock(&mm->page_table_lock);
- if (!pte_none(*page_table)) {
- page_cache_release(page);
- spin_unlock(&mm->page_table_lock);
- return 1;
- }
- mm->rss++;
- flush_page_to_ram(page);
- entry = pte_mkwrite(pte_mkdirty(mk_pte(page, vma->vm_page_prot)));
- lru_cache_add(page);
- mark_page_accessed(page);
- }
-
- set_pte(page_table, entry);
-
- /* No need to invalidate - it was non-present before */
- update_mmu_cache(vma, addr, entry);
- XENO_flush_page_update_queue();
- spin_unlock(&mm->page_table_lock);
- return 1; /* Minor fault */
-
-no_mem:
- return -1;
-}
-
-/*
- * do_no_page() tries to create a new page mapping. It aggressively
- * tries to share with existing pages, but makes a separate copy if
- * the "write_access" parameter is true in order to avoid the next
- * page fault.
- *
- * As this is called only for pages that do not currently exist, we
- * do not need to flush old virtual caches or the TLB.
- *
- * This is called with the MM semaphore held and the page table
- * spinlock held. Exit with the spinlock released.
- */
-static int do_no_page(struct mm_struct * mm, struct vm_area_struct * vma,
- unsigned long address, int write_access, pte_t *page_table)
-{
- struct page * new_page;
- pte_t entry;
-
- if (!vma->vm_ops || !vma->vm_ops->nopage)
- return do_anonymous_page(mm, vma, page_table, write_access, address);
- spin_unlock(&mm->page_table_lock);
-
- new_page = vma->vm_ops->nopage(vma, address & PAGE_MASK, 0);
-
- if (new_page == NULL) /* no page was available -- SIGBUS */
- return 0;
- if (new_page == NOPAGE_OOM)
- return -1;
-
- /*
- * Should we do an early C-O-W break?
- */
- if (write_access && !(vma->vm_flags & VM_SHARED)) {
- struct page * page = alloc_page(GFP_HIGHUSER);
- if (!page) {
- page_cache_release(new_page);
- return -1;
- }
- copy_user_highpage(page, new_page, address);
- page_cache_release(new_page);
- lru_cache_add(page);
- new_page = page;
- }
-
- spin_lock(&mm->page_table_lock);
- /*
- * This silly early PAGE_DIRTY setting removes a race
- * due to the bad i386 page protection. But it's valid
- * for other architectures too.
- *
- * Note that if write_access is true, we either now have
- * an exclusive copy of the page, or this is a shared mapping,
- * so we can make it writable and dirty to avoid having to
- * handle that later.
- */
- /* Only go through if we didn't race with anybody else... */
- if (pte_none(*page_table)) {
- ++mm->rss;
- flush_page_to_ram(new_page);
- flush_icache_page(vma, new_page);
- entry = mk_pte(new_page, vma->vm_page_prot);
- if (write_access)
- entry = pte_mkwrite(pte_mkdirty(entry));
- set_pte(page_table, entry);
- } else {
- /* One of our sibling threads was faster, back out. */
- page_cache_release(new_page);
- spin_unlock(&mm->page_table_lock);
- return 1;
- }
-
- /* no need to invalidate: a not-present page shouldn't be cached */
- update_mmu_cache(vma, address, entry);
- XENO_flush_page_update_queue();
- spin_unlock(&mm->page_table_lock);
- return 2; /* Major fault */
-}
-
-/*
- * These routines also need to handle stuff like marking pages dirty
- * and/or accessed for architectures that don't do it in hardware (most
- * RISC architectures). The early dirtying is also good on the i386.
- *
- * There is also a hook called "update_mmu_cache()" that architectures
- * with external mmu caches can use to update those (ie the Sparc or
- * PowerPC hashed page tables that act as extended TLBs).
- *
- * Note the "page_table_lock". It is to protect against kswapd removing
- * pages from under us. Note that kswapd only ever _removes_ pages, never
- * adds them. As such, once we have noticed that the page is not present,
- * we can drop the lock early.
- *
- * The adding of pages is protected by the MM semaphore (which we hold),
- * so we don't need to worry about a page being suddenly been added into
- * our VM.
- *
- * We enter with the pagetable spinlock held, we are supposed to
- * release it when done.
- */
-static inline int handle_pte_fault(struct mm_struct *mm,
- struct vm_area_struct * vma, unsigned long address,
- int write_access, pte_t * pte)
-{
- pte_t entry;
-
- entry = *pte;
- if (!pte_present(entry)) {
- /*
- * If it truly wasn't present, we know that kswapd
- * and the PTE updates will not touch it later. So
- * drop the lock.
- */
- if (pte_none(entry))
- return do_no_page(mm, vma, address, write_access, pte);
- return do_swap_page(mm, vma, address, pte, entry, write_access);
- }
-
- if (write_access) {
- if (!pte_write(entry))
- return do_wp_page(mm, vma, address, pte, entry);
-
- entry = pte_mkdirty(entry);
- }
- entry = pte_mkyoung(entry);
- establish_pte(vma, address, pte, entry);
- XENO_flush_page_update_queue();
- spin_unlock(&mm->page_table_lock);
- return 1;
-}
-
-/*
- * By the time we get here, we already hold the mm semaphore
- */
-int handle_mm_fault(struct mm_struct *mm, struct vm_area_struct * vma,
- unsigned long address, int write_access)
-{
- pgd_t *pgd;
- pmd_t *pmd;
-
- current->state = TASK_RUNNING;
- pgd = pgd_offset(mm, address);
-
- /*
- * We need the page table lock to synchronize with kswapd
- * and the SMP-safe atomic PTE updates.
- */
- spin_lock(&mm->page_table_lock);
- pmd = pmd_alloc(mm, pgd, address);
-
- if (pmd) {
- pte_t * pte = pte_alloc(mm, pmd, address);
- if (pte)
- return handle_pte_fault(mm, vma, address, write_access, pte);
- }
- spin_unlock(&mm->page_table_lock);
- return -1;
-}
-
-/*
- * Allocate page middle directory.
- *
- * We've already handled the fast-path in-line, and we own the
- * page table lock.
- *
- * On a two-level page table, this ends up actually being entirely
- * optimized away.
- */
-pmd_t *__pmd_alloc(struct mm_struct *mm, pgd_t *pgd, unsigned long address)
-{
- pmd_t *new;
-
- /* "fast" allocation can happen without dropping the lock.. */
- new = pmd_alloc_one_fast(mm, address);
- if (!new) {
- spin_unlock(&mm->page_table_lock);
- new = pmd_alloc_one(mm, address);
- spin_lock(&mm->page_table_lock);
- if (!new)
- return NULL;
-
- /*
- * Because we dropped the lock, we should re-check the
- * entry, as somebody else could have populated it..
- */
- if (!pgd_none(*pgd)) {
- pmd_free(new);
- goto out;
- }
- }
- pgd_populate(mm, pgd, new);
-out:
- return pmd_offset(pgd, address);
-}
-
-/*
- * Allocate the page table directory.
- *
- * We've already handled the fast-path in-line, and we own the
- * page table lock.
- */
-pte_t *pte_alloc(struct mm_struct *mm, pmd_t *pmd, unsigned long address)
-{
- if (pmd_none(*pmd)) {
- pte_t *new;
-
- /* "fast" allocation can happen without dropping the lock.. */
- new = pte_alloc_one_fast(mm, address);
- if (!new) {
- XENO_flush_page_update_queue();
- spin_unlock(&mm->page_table_lock);
- new = pte_alloc_one(mm, address);
- spin_lock(&mm->page_table_lock);
- if (!new)
- return NULL;
-
- /*
- * Because we dropped the lock, we should re-check the
- * entry, as somebody else could have populated it..
- */
- if (!pmd_none(*pmd)) {
- pte_free(new);
- goto out;
- }
- }
- pmd_populate(mm, pmd, new);
- }
-out:
- return pte_offset(pmd, address);
-}
-
-int make_pages_present(unsigned long addr, unsigned long end)
-{
- int ret, len, write;
- struct vm_area_struct * vma;
-
- vma = find_vma(current->mm, addr);
- write = (vma->vm_flags & VM_WRITE) != 0;
- if (addr >= end)
- BUG();
- if (end > vma->vm_end)
- BUG();
- len = (end+PAGE_SIZE-1)/PAGE_SIZE-addr/PAGE_SIZE;
- ret = get_user_pages(current, current->mm, addr,
- len, write, 0, NULL, NULL);
- return ret == len ? 0 : -1;
-}
-
-struct page * vmalloc_to_page(void * vmalloc_addr)
-{
- unsigned long addr = (unsigned long) vmalloc_addr;
- struct page *page = NULL;
- pmd_t *pmd;
- pte_t *pte;
- pgd_t *pgd;
-
- pgd = pgd_offset_k(addr);
- if (!pgd_none(*pgd)) {
- pmd = pmd_offset(pgd, addr);
- if (!pmd_none(*pmd)) {
- pte = pte_offset(pmd, addr);
- if (pte_present(*pte)) {
- page = pte_page(*pte);
- }
- }
- }
- return page;
-}
+++ /dev/null
-/*
- * linux/mm/remap.c
- *
- * (C) Copyright 1996 Linus Torvalds
- */
-
-#include <linux/slab.h>
-#include <linux/smp_lock.h>
-#include <linux/shm.h>
-#include <linux/mman.h>
-#include <linux/swap.h>
-
-#include <asm/uaccess.h>
-#include <asm/pgalloc.h>
-
-extern int vm_enough_memory(long pages);
-
-static inline pte_t *get_one_pte(struct mm_struct *mm, unsigned long addr)
-{
- pgd_t * pgd;
- pmd_t * pmd;
- pte_t * pte = NULL;
-
- pgd = pgd_offset(mm, addr);
- if (pgd_none(*pgd))
- goto end;
- if (pgd_bad(*pgd)) {
- pgd_ERROR(*pgd);
- pgd_clear(pgd);
- goto end;
- }
-
- pmd = pmd_offset(pgd, addr);
- if (pmd_none(*pmd))
- goto end;
- if (pmd_bad(*pmd)) {
- pmd_ERROR(*pmd);
- pmd_clear(pmd);
- goto end;
- }
-
- pte = pte_offset(pmd, addr);
- if (pte_none(*pte))
- pte = NULL;
-end:
- return pte;
-}
-
-static inline pte_t *alloc_one_pte(struct mm_struct *mm, unsigned long addr)
-{
- pmd_t * pmd;
- pte_t * pte = NULL;
-
- pmd = pmd_alloc(mm, pgd_offset(mm, addr), addr);
- if (pmd)
- pte = pte_alloc(mm, pmd, addr);
- return pte;
-}
-
-static inline int copy_one_pte(struct mm_struct *mm, pte_t * src, pte_t * dst)
-{
- int error = 0;
- pte_t pte;
-
- if (!pte_none(*src)) {
- pte = ptep_get_and_clear(src);
- if (!dst) {
- /* No dest? We must put it back. */
- dst = src;
- error++;
- }
- set_pte(dst, pte);
- }
- return error;
-}
-
-static int move_one_page(struct mm_struct *mm, unsigned long old_addr, unsigned long new_addr)
-{
- int error = 0;
- pte_t * src;
-
- spin_lock(&mm->page_table_lock);
- src = get_one_pte(mm, old_addr);
- if (src)
- error = copy_one_pte(mm, src, alloc_one_pte(mm, new_addr));
- spin_unlock(&mm->page_table_lock);
- return error;
-}
-
-static int move_page_tables(struct mm_struct * mm,
- unsigned long new_addr, unsigned long old_addr, unsigned long len)
-{
- unsigned long offset = len;
-
- flush_cache_range(mm, old_addr, old_addr + len);
-
- /*
- * This is not the clever way to do this, but we're taking the
- * easy way out on the assumption that most remappings will be
- * only a few pages.. This also makes error recovery easier.
- */
- while (offset) {
- offset -= PAGE_SIZE;
- if (move_one_page(mm, old_addr + offset, new_addr + offset))
- goto oops_we_failed;
- }
- flush_tlb_range(mm, old_addr, old_addr + len);
- return 0;
-
- /*
- * Ok, the move failed because we didn't have enough pages for
- * the new page table tree. This is unlikely, but we have to
- * take the possibility into account. In that case we just move
- * all the pages back (this will work, because we still have
- * the old page tables)
- */
-oops_we_failed:
- XENO_flush_page_update_queue();
- flush_cache_range(mm, new_addr, new_addr + len);
- while ((offset += PAGE_SIZE) < len)
- move_one_page(mm, new_addr + offset, old_addr + offset);
- XENO_flush_page_update_queue();
- zap_page_range(mm, new_addr, len);
- return -1;
-}
-
-static inline unsigned long move_vma(struct vm_area_struct * vma,
- unsigned long addr, unsigned long old_len, unsigned long new_len,
- unsigned long new_addr)
-{
- struct mm_struct * mm = vma->vm_mm;
- struct vm_area_struct * new_vma, * next, * prev;
- int allocated_vma;
-
- new_vma = NULL;
- next = find_vma_prev(mm, new_addr, &prev);
- if (next) {
- if (prev && prev->vm_end == new_addr &&
- can_vma_merge(prev, vma->vm_flags) && !vma->vm_file && !(vma->vm_flags & VM_SHARED)) {
- spin_lock(&mm->page_table_lock);
- prev->vm_end = new_addr + new_len;
- spin_unlock(&mm->page_table_lock);
- new_vma = prev;
- if (next != prev->vm_next)
- BUG();
- if (prev->vm_end == next->vm_start && can_vma_merge(next, prev->vm_flags)) {
- spin_lock(&mm->page_table_lock);
- prev->vm_end = next->vm_end;
- __vma_unlink(mm, next, prev);
- spin_unlock(&mm->page_table_lock);
-
- mm->map_count--;
- kmem_cache_free(vm_area_cachep, next);
- }
- } else if (next->vm_start == new_addr + new_len &&
- can_vma_merge(next, vma->vm_flags) && !vma->vm_file && !(vma->vm_flags & VM_SHARED)) {
- spin_lock(&mm->page_table_lock);
- next->vm_start = new_addr;
- spin_unlock(&mm->page_table_lock);
- new_vma = next;
- }
- } else {
- prev = find_vma(mm, new_addr-1);
- if (prev && prev->vm_end == new_addr &&
- can_vma_merge(prev, vma->vm_flags) && !vma->vm_file && !(vma->vm_flags & VM_SHARED)) {
- spin_lock(&mm->page_table_lock);
- prev->vm_end = new_addr + new_len;
- spin_unlock(&mm->page_table_lock);
- new_vma = prev;
- }
- }
-
- allocated_vma = 0;
- if (!new_vma) {
- new_vma = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL);
- if (!new_vma)
- goto out;
- allocated_vma = 1;
- }
-
- if (!move_page_tables(current->mm, new_addr, addr, old_len)) {
- if (allocated_vma) {
- *new_vma = *vma;
- new_vma->vm_start = new_addr;
- new_vma->vm_end = new_addr+new_len;
- new_vma->vm_pgoff += (addr - vma->vm_start) >> PAGE_SHIFT;
- new_vma->vm_raend = 0;
- if (new_vma->vm_file)
- get_file(new_vma->vm_file);
- if (new_vma->vm_ops && new_vma->vm_ops->open)
- new_vma->vm_ops->open(new_vma);
- insert_vm_struct(current->mm, new_vma);
- }
- do_munmap(current->mm, addr, old_len);
- current->mm->total_vm += new_len >> PAGE_SHIFT;
- if (new_vma->vm_flags & VM_LOCKED) {
- current->mm->locked_vm += new_len >> PAGE_SHIFT;
- make_pages_present(new_vma->vm_start,
- new_vma->vm_end);
- }
- return new_addr;
- }
- if (allocated_vma)
- kmem_cache_free(vm_area_cachep, new_vma);
- out:
- return -ENOMEM;
-}
-
-/*
- * Expand (or shrink) an existing mapping, potentially moving it at the
- * same time (controlled by the MREMAP_MAYMOVE flag and available VM space)
- *
- * MREMAP_FIXED option added 5-Dec-1999 by Benjamin LaHaise
- * This option implies MREMAP_MAYMOVE.
- */
-unsigned long do_mremap(unsigned long addr,
- unsigned long old_len, unsigned long new_len,
- unsigned long flags, unsigned long new_addr)
-{
- struct vm_area_struct *vma;
- unsigned long ret = -EINVAL;
-
- if (flags & ~(MREMAP_FIXED | MREMAP_MAYMOVE))
- goto out;
-
- if (addr & ~PAGE_MASK)
- goto out;
-
- old_len = PAGE_ALIGN(old_len);
- new_len = PAGE_ALIGN(new_len);
-
- /* new_addr is only valid if MREMAP_FIXED is specified */
- if (flags & MREMAP_FIXED) {
- if (new_addr & ~PAGE_MASK)
- goto out;
- if (!(flags & MREMAP_MAYMOVE))
- goto out;
-
- if (new_len > TASK_SIZE || new_addr > TASK_SIZE - new_len)
- goto out;
-
- /* Check if the location we're moving into overlaps the
- * old location at all, and fail if it does.
- */
- if ((new_addr <= addr) && (new_addr+new_len) > addr)
- goto out;
-
- if ((addr <= new_addr) && (addr+old_len) > new_addr)
- goto out;
-
- do_munmap(current->mm, new_addr, new_len);
- }
-
- /*
- * Always allow a shrinking remap: that just unmaps
- * the unnecessary pages..
- */
- ret = addr;
- if (old_len >= new_len) {
- do_munmap(current->mm, addr+new_len, old_len - new_len);
- if (!(flags & MREMAP_FIXED) || (new_addr == addr))
- goto out;
- }
-
- /*
- * Ok, we need to grow.. or relocate.
- */
- ret = -EFAULT;
- vma = find_vma(current->mm, addr);
- if (!vma || vma->vm_start > addr)
- goto out;
- /* We can't remap across vm area boundaries */
- if (old_len > vma->vm_end - addr)
- goto out;
- if (vma->vm_flags & VM_DONTEXPAND) {
- if (new_len > old_len)
- goto out;
- }
- if (vma->vm_flags & VM_LOCKED) {
- unsigned long locked = current->mm->locked_vm << PAGE_SHIFT;
- locked += new_len - old_len;
- ret = -EAGAIN;
- if (locked > current->rlim[RLIMIT_MEMLOCK].rlim_cur)
- goto out;
- }
- ret = -ENOMEM;
- if ((current->mm->total_vm << PAGE_SHIFT) + (new_len - old_len)
- > current->rlim[RLIMIT_AS].rlim_cur)
- goto out;
- /* Private writable mapping? Check memory availability.. */
- if ((vma->vm_flags & (VM_SHARED | VM_WRITE)) == VM_WRITE &&
- !(flags & MAP_NORESERVE) &&
- !vm_enough_memory((new_len - old_len) >> PAGE_SHIFT))
- goto out;
-
- /* old_len exactly to the end of the area..
- * And we're not relocating the area.
- */
- if (old_len == vma->vm_end - addr &&
- !((flags & MREMAP_FIXED) && (addr != new_addr)) &&
- (old_len != new_len || !(flags & MREMAP_MAYMOVE))) {
- unsigned long max_addr = TASK_SIZE;
- if (vma->vm_next)
- max_addr = vma->vm_next->vm_start;
- /* can we just expand the current mapping? */
- if (max_addr - addr >= new_len) {
- int pages = (new_len - old_len) >> PAGE_SHIFT;
- spin_lock(&vma->vm_mm->page_table_lock);
- vma->vm_end = addr + new_len;
- spin_unlock(&vma->vm_mm->page_table_lock);
- current->mm->total_vm += pages;
- if (vma->vm_flags & VM_LOCKED) {
- current->mm->locked_vm += pages;
- make_pages_present(addr + old_len,
- addr + new_len);
- }
- ret = addr;
- goto out;
- }
- }
-
- /*
- * We weren't able to just expand or shrink the area,
- * we need to create a new one and move it..
- */
- ret = -ENOMEM;
- if (flags & MREMAP_MAYMOVE) {
- if (!(flags & MREMAP_FIXED)) {
- unsigned long map_flags = 0;
- if (vma->vm_flags & VM_SHARED)
- map_flags |= MAP_SHARED;
-
- new_addr = get_unmapped_area(vma->vm_file, 0, new_len, vma->vm_pgoff, map_flags);
- ret = new_addr;
- if (new_addr & ~PAGE_MASK)
- goto out;
- }
- ret = move_vma(vma, addr, old_len, new_len, new_addr);
- }
-out:
- return ret;
-}
-
-asmlinkage unsigned long sys_mremap(unsigned long addr,
- unsigned long old_len, unsigned long new_len,
- unsigned long flags, unsigned long new_addr)
-{
- unsigned long ret;
-
- down_write(¤t->mm->mmap_sem);
- ret = do_mremap(addr, old_len, new_len, flags, new_addr);
- up_write(¤t->mm->mmap_sem);
- return ret;
-}
+++ /dev/null
-/*
- * linux/mm/swapfile.c
- *
- * Copyright (C) 1991, 1992, 1993, 1994 Linus Torvalds
- * Swap reorganised 29.12.95, Stephen Tweedie
- */
-
-#include <linux/slab.h>
-#include <linux/smp_lock.h>
-#include <linux/kernel_stat.h>
-#include <linux/swap.h>
-#include <linux/swapctl.h>
-#include <linux/blkdev.h> /* for blk_size */
-#include <linux/vmalloc.h>
-#include <linux/pagemap.h>
-#include <linux/shm.h>
-
-#include <asm/pgtable.h>
-
-spinlock_t swaplock = SPIN_LOCK_UNLOCKED;
-unsigned int nr_swapfiles;
-int total_swap_pages;
-static int swap_overflow;
-
-static const char Bad_file[] = "Bad swap file entry ";
-static const char Unused_file[] = "Unused swap file entry ";
-static const char Bad_offset[] = "Bad swap offset entry ";
-static const char Unused_offset[] = "Unused swap offset entry ";
-
-struct swap_list_t swap_list = {-1, -1};
-
-struct swap_info_struct swap_info[MAX_SWAPFILES];
-
-#define SWAPFILE_CLUSTER 256
-
-static inline int scan_swap_map(struct swap_info_struct *si)
-{
- unsigned long offset;
- /*
- * We try to cluster swap pages by allocating them
- * sequentially in swap. Once we've allocated
- * SWAPFILE_CLUSTER pages this way, however, we resort to
- * first-free allocation, starting a new cluster. This
- * prevents us from scattering swap pages all over the entire
- * swap partition, so that we reduce overall disk seek times
- * between swap pages. -- sct */
- if (si->cluster_nr) {
- while (si->cluster_next <= si->highest_bit) {
- offset = si->cluster_next++;
- if (si->swap_map[offset])
- continue;
- si->cluster_nr--;
- goto got_page;
- }
- }
- si->cluster_nr = SWAPFILE_CLUSTER;
-
- /* try to find an empty (even not aligned) cluster. */
- offset = si->lowest_bit;
- check_next_cluster:
- if (offset+SWAPFILE_CLUSTER-1 <= si->highest_bit)
- {
- int nr;
- for (nr = offset; nr < offset+SWAPFILE_CLUSTER; nr++)
- if (si->swap_map[nr])
- {
- offset = nr+1;
- goto check_next_cluster;
- }
- /* We found a completly empty cluster, so start
- * using it.
- */
- goto got_page;
- }
- /* No luck, so now go finegrined as usual. -Andrea */
- for (offset = si->lowest_bit; offset <= si->highest_bit ; offset++) {
- if (si->swap_map[offset])
- continue;
- si->lowest_bit = offset+1;
- got_page:
- if (offset == si->lowest_bit)
- si->lowest_bit++;
- if (offset == si->highest_bit)
- si->highest_bit--;
- if (si->lowest_bit > si->highest_bit) {
- si->lowest_bit = si->max;
- si->highest_bit = 0;
- }
- si->swap_map[offset] = 1;
- nr_swap_pages--;
- si->cluster_next = offset+1;
- return offset;
- }
- si->lowest_bit = si->max;
- si->highest_bit = 0;
- return 0;
-}
-
-swp_entry_t get_swap_page(void)
-{
- struct swap_info_struct * p;
- unsigned long offset;
- swp_entry_t entry;
- int type, wrapped = 0;
-
- entry.val = 0; /* Out of memory */
- swap_list_lock();
- type = swap_list.next;
- if (type < 0)
- goto out;
- if (nr_swap_pages <= 0)
- goto out;
-
- while (1) {
- p = &swap_info[type];
- if ((p->flags & SWP_WRITEOK) == SWP_WRITEOK) {
- swap_device_lock(p);
- offset = scan_swap_map(p);
- swap_device_unlock(p);
- if (offset) {
- entry = SWP_ENTRY(type,offset);
- type = swap_info[type].next;
- if (type < 0 ||
- p->prio != swap_info[type].prio) {
- swap_list.next = swap_list.head;
- } else {
- swap_list.next = type;
- }
- goto out;
- }
- }
- type = p->next;
- if (!wrapped) {
- if (type < 0 || p->prio != swap_info[type].prio) {
- type = swap_list.head;
- wrapped = 1;
- }
- } else
- if (type < 0)
- goto out; /* out of swap space */
- }
-out:
- swap_list_unlock();
- return entry;
-}
-
-static struct swap_info_struct * swap_info_get(swp_entry_t entry)
-{
- struct swap_info_struct * p;
- unsigned long offset, type;
-
- if (!entry.val)
- goto out;
- type = SWP_TYPE(entry);
- if (type >= nr_swapfiles)
- goto bad_nofile;
- p = & swap_info[type];
- if (!(p->flags & SWP_USED))
- goto bad_device;
- offset = SWP_OFFSET(entry);
- if (offset >= p->max)
- goto bad_offset;
- if (!p->swap_map[offset])
- goto bad_free;
- swap_list_lock();
- if (p->prio > swap_info[swap_list.next].prio)
- swap_list.next = type;
- swap_device_lock(p);
- return p;
-
-bad_free:
- printk(KERN_ERR "swap_free: %s%08lx\n", Unused_offset, entry.val);
- goto out;
-bad_offset:
- printk(KERN_ERR "swap_free: %s%08lx\n", Bad_offset, entry.val);
- goto out;
-bad_device:
- printk(KERN_ERR "swap_free: %s%08lx\n", Unused_file, entry.val);
- goto out;
-bad_nofile:
- printk(KERN_ERR "swap_free: %s%08lx\n", Bad_file, entry.val);
-out:
- return NULL;
-}
-
-static void swap_info_put(struct swap_info_struct * p)
-{
- swap_device_unlock(p);
- swap_list_unlock();
-}
-
-static int swap_entry_free(struct swap_info_struct *p, unsigned long offset)
-{
- int count = p->swap_map[offset];
-
- if (count < SWAP_MAP_MAX) {
- count--;
- p->swap_map[offset] = count;
- if (!count) {
- if (offset < p->lowest_bit)
- p->lowest_bit = offset;
- if (offset > p->highest_bit)
- p->highest_bit = offset;
- nr_swap_pages++;
- }
- }
- return count;
-}
-
-/*
- * Caller has made sure that the swapdevice corresponding to entry
- * is still around or has not been recycled.
- */
-void swap_free(swp_entry_t entry)
-{
- struct swap_info_struct * p;
-
- p = swap_info_get(entry);
- if (p) {
- swap_entry_free(p, SWP_OFFSET(entry));
- swap_info_put(p);
- }
-}
-
-/*
- * Check if we're the only user of a swap page,
- * when the page is locked.
- */
-static int exclusive_swap_page(struct page *page)
-{
- int retval = 0;
- struct swap_info_struct * p;
- swp_entry_t entry;
-
- entry.val = page->index;
- p = swap_info_get(entry);
- if (p) {
- /* Is the only swap cache user the cache itself? */
- if (p->swap_map[SWP_OFFSET(entry)] == 1) {
- /* Recheck the page count with the pagecache lock held.. */
- spin_lock(&pagecache_lock);
- if (page_count(page) - !!page->buffers == 2)
- retval = 1;
- spin_unlock(&pagecache_lock);
- }
- swap_info_put(p);
- }
- return retval;
-}
-
-/*
- * We can use this swap cache entry directly
- * if there are no other references to it.
- *
- * Here "exclusive_swap_page()" does the real
- * work, but we opportunistically check whether
- * we need to get all the locks first..
- */
-int can_share_swap_page(struct page *page)
-{
- int retval = 0;
-
- if (!PageLocked(page))
- BUG();
- switch (page_count(page)) {
- case 3:
- if (!page->buffers)
- break;
- /* Fallthrough */
- case 2:
- if (!PageSwapCache(page))
- break;
- retval = exclusive_swap_page(page);
- break;
- case 1:
- if (PageReserved(page))
- break;
- retval = 1;
- }
- return retval;
-}
-
-/*
- * Work out if there are any other processes sharing this
- * swap cache page. Free it if you can. Return success.
- */
-int remove_exclusive_swap_page(struct page *page)
-{
- int retval;
- struct swap_info_struct * p;
- swp_entry_t entry;
-
- if (!PageLocked(page))
- BUG();
- if (!PageSwapCache(page))
- return 0;
- if (page_count(page) - !!page->buffers != 2) /* 2: us + cache */
- return 0;
-
- entry.val = page->index;
- p = swap_info_get(entry);
- if (!p)
- return 0;
-
- /* Is the only swap cache user the cache itself? */
- retval = 0;
- if (p->swap_map[SWP_OFFSET(entry)] == 1) {
- /* Recheck the page count with the pagecache lock held.. */
- spin_lock(&pagecache_lock);
- if (page_count(page) - !!page->buffers == 2) {
- __delete_from_swap_cache(page);
- SetPageDirty(page);
- retval = 1;
- }
- spin_unlock(&pagecache_lock);
- }
- swap_info_put(p);
-
- if (retval) {
- block_flushpage(page, 0);
- swap_free(entry);
- page_cache_release(page);
- }
-
- return retval;
-}
-
-/*
- * Free the swap entry like above, but also try to
- * free the page cache entry if it is the last user.
- */
-void free_swap_and_cache(swp_entry_t entry)
-{
- struct swap_info_struct * p;
- struct page *page = NULL;
-
- p = swap_info_get(entry);
- if (p) {
- if (swap_entry_free(p, SWP_OFFSET(entry)) == 1)
- page = find_trylock_page(&swapper_space, entry.val);
- swap_info_put(p);
- }
- if (page) {
- page_cache_get(page);
- /* Only cache user (+us), or swap space full? Free it! */
- if (page_count(page) - !!page->buffers == 2 || vm_swap_full()) {
- delete_from_swap_cache(page);
- SetPageDirty(page);
- }
- UnlockPage(page);
- page_cache_release(page);
- }
-}
-
-/*
- * The swap entry has been read in advance, and we return 1 to indicate
- * that the page has been used or is no longer needed.
- *
- * Always set the resulting pte to be nowrite (the same as COW pages
- * after one process has exited). We don't know just how many PTEs will
- * share this swap entry, so be cautious and let do_wp_page work out
- * what to do if a write is requested later.
- */
-/* mmlist_lock and vma->vm_mm->page_table_lock are held */
-static inline void unuse_pte(struct vm_area_struct * vma, unsigned long address,
- pte_t *dir, swp_entry_t entry, struct page* page)
-{
- pte_t pte = *dir;
-
- if (likely(pte_to_swp_entry(pte).val != entry.val))
- return;
- if (unlikely(pte_none(pte) || pte_present(pte)))
- return;
- get_page(page);
- set_pte(dir, pte_mkold(mk_pte(page, vma->vm_page_prot)));
- swap_free(entry);
- ++vma->vm_mm->rss;
-}
-
-/* mmlist_lock and vma->vm_mm->page_table_lock are held */
-static inline void unuse_pmd(struct vm_area_struct * vma, pmd_t *dir,
- unsigned long address, unsigned long size, unsigned long offset,
- swp_entry_t entry, struct page* page)
-{
- pte_t * pte;
- unsigned long end;
-
- if (pmd_none(*dir))
- return;
- if (pmd_bad(*dir)) {
- pmd_ERROR(*dir);
- pmd_clear(dir);
- return;
- }
- pte = pte_offset(dir, address);
- offset += address & PMD_MASK;
- address &= ~PMD_MASK;
- end = address + size;
- if (end > PMD_SIZE)
- end = PMD_SIZE;
- do {
- unuse_pte(vma, offset+address-vma->vm_start, pte, entry, page);
- address += PAGE_SIZE;
- pte++;
- } while (address && (address < end));
-}
-
-/* mmlist_lock and vma->vm_mm->page_table_lock are held */
-static inline void unuse_pgd(struct vm_area_struct * vma, pgd_t *dir,
- unsigned long address, unsigned long size,
- swp_entry_t entry, struct page* page)
-{
- pmd_t * pmd;
- unsigned long offset, end;
-
- if (pgd_none(*dir))
- return;
- if (pgd_bad(*dir)) {
- pgd_ERROR(*dir);
- pgd_clear(dir);
- return;
- }
- pmd = pmd_offset(dir, address);
- offset = address & PGDIR_MASK;
- address &= ~PGDIR_MASK;
- end = address + size;
- if (end > PGDIR_SIZE)
- end = PGDIR_SIZE;
- if (address >= end)
- BUG();
- do {
- unuse_pmd(vma, pmd, address, end - address, offset, entry,
- page);
- address = (address + PMD_SIZE) & PMD_MASK;
- pmd++;
- } while (address && (address < end));
-}
-
-/* mmlist_lock and vma->vm_mm->page_table_lock are held */
-static void unuse_vma(struct vm_area_struct * vma, pgd_t *pgdir,
- swp_entry_t entry, struct page* page)
-{
- unsigned long start = vma->vm_start, end = vma->vm_end;
-
- if (start >= end)
- BUG();
- do {
- unuse_pgd(vma, pgdir, start, end - start, entry, page);
- start = (start + PGDIR_SIZE) & PGDIR_MASK;
- pgdir++;
- } while (start && (start < end));
-}
-
-static void unuse_process(struct mm_struct * mm,
- swp_entry_t entry, struct page* page)
-{
- struct vm_area_struct* vma;
-
- /*
- * Go through process' page directory.
- */
- spin_lock(&mm->page_table_lock);
- for (vma = mm->mmap; vma; vma = vma->vm_next) {
- pgd_t * pgd = pgd_offset(mm, vma->vm_start);
- unuse_vma(vma, pgd, entry, page);
- }
- XENO_flush_page_update_queue();
- spin_unlock(&mm->page_table_lock);
- return;
-}
-
-/*
- * Scan swap_map from current position to next entry still in use.
- * Recycle to start on reaching the end, returning 0 when empty.
- */
-static int find_next_to_unuse(struct swap_info_struct *si, int prev)
-{
- int max = si->max;
- int i = prev;
- int count;
-
- /*
- * No need for swap_device_lock(si) here: we're just looking
- * for whether an entry is in use, not modifying it; false
- * hits are okay, and sys_swapoff() has already prevented new
- * allocations from this area (while holding swap_list_lock()).
- */
- for (;;) {
- if (++i >= max) {
- if (!prev) {
- i = 0;
- break;
- }
- /*
- * No entries in use at top of swap_map,
- * loop back to start and recheck there.
- */
- max = prev + 1;
- prev = 0;
- i = 1;
- }
- count = si->swap_map[i];
- if (count && count != SWAP_MAP_BAD)
- break;
- }
- return i;
-}
-
-/*
- * We completely avoid races by reading each swap page in advance,
- * and then search for the process using it. All the necessary
- * page table adjustments can then be made atomically.
- */
-static int try_to_unuse(unsigned int type)
-{
- struct swap_info_struct * si = &swap_info[type];
- struct mm_struct *start_mm;
- unsigned short *swap_map;
- unsigned short swcount;
- struct page *page;
- swp_entry_t entry;
- int i = 0;
- int retval = 0;
- int reset_overflow = 0;
-
- /*
- * When searching mms for an entry, a good strategy is to
- * start at the first mm we freed the previous entry from
- * (though actually we don't notice whether we or coincidence
- * freed the entry). Initialize this start_mm with a hold.
- *
- * A simpler strategy would be to start at the last mm we
- * freed the previous entry from; but that would take less
- * advantage of mmlist ordering (now preserved by swap_out()),
- * which clusters forked address spaces together, most recent
- * child immediately after parent. If we race with dup_mmap(),
- * we very much want to resolve parent before child, otherwise
- * we may miss some entries: using last mm would invert that.
- */
- start_mm = &init_mm;
- atomic_inc(&init_mm.mm_users);
-
- /*
- * Keep on scanning until all entries have gone. Usually,
- * one pass through swap_map is enough, but not necessarily:
- * mmput() removes mm from mmlist before exit_mmap() and its
- * zap_page_range(). That's not too bad, those entries are
- * on their way out, and handled faster there than here.
- * do_munmap() behaves similarly, taking the range out of mm's
- * vma list before zap_page_range(). But unfortunately, when
- * unmapping a part of a vma, it takes the whole out first,
- * then reinserts what's left after (might even reschedule if
- * open() method called) - so swap entries may be invisible
- * to swapoff for a while, then reappear - but that is rare.
- */
- while ((i = find_next_to_unuse(si, i))) {
- /*
- * Get a page for the entry, using the existing swap
- * cache page if there is one. Otherwise, get a clean
- * page and read the swap into it.
- */
- swap_map = &si->swap_map[i];
- entry = SWP_ENTRY(type, i);
- page = read_swap_cache_async(entry);
- if (!page) {
- /*
- * Either swap_duplicate() failed because entry
- * has been freed independently, and will not be
- * reused since sys_swapoff() already disabled
- * allocation from here, or alloc_page() failed.
- */
- if (!*swap_map)
- continue;
- retval = -ENOMEM;
- break;
- }
-
- /*
- * Don't hold on to start_mm if it looks like exiting.
- */
- if (atomic_read(&start_mm->mm_users) == 1) {
- mmput(start_mm);
- start_mm = &init_mm;
- atomic_inc(&init_mm.mm_users);
- }
-
- /*
- * Wait for and lock page. When do_swap_page races with
- * try_to_unuse, do_swap_page can handle the fault much
- * faster than try_to_unuse can locate the entry. This
- * apparently redundant "wait_on_page" lets try_to_unuse
- * defer to do_swap_page in such a case - in some tests,
- * do_swap_page and try_to_unuse repeatedly compete.
- */
- wait_on_page(page);
- lock_page(page);
-
- /*
- * Remove all references to entry, without blocking.
- * Whenever we reach init_mm, there's no address space
- * to search, but use it as a reminder to search shmem.
- */
- swcount = *swap_map;
- if (swcount > 1) {
- flush_page_to_ram(page);
- if (start_mm == &init_mm)
- shmem_unuse(entry, page);
- else
- unuse_process(start_mm, entry, page);
- }
- if (*swap_map > 1) {
- int set_start_mm = (*swap_map >= swcount);
- struct list_head *p = &start_mm->mmlist;
- struct mm_struct *new_start_mm = start_mm;
- struct mm_struct *mm;
-
- spin_lock(&mmlist_lock);
- while (*swap_map > 1 &&
- (p = p->next) != &start_mm->mmlist) {
- mm = list_entry(p, struct mm_struct, mmlist);
- swcount = *swap_map;
- if (mm == &init_mm) {
- set_start_mm = 1;
- shmem_unuse(entry, page);
- } else
- unuse_process(mm, entry, page);
- if (set_start_mm && *swap_map < swcount) {
- new_start_mm = mm;
- set_start_mm = 0;
- }
- }
- atomic_inc(&new_start_mm->mm_users);
- spin_unlock(&mmlist_lock);
- mmput(start_mm);
- start_mm = new_start_mm;
- }
-
- /*
- * How could swap count reach 0x7fff when the maximum
- * pid is 0x7fff, and there's no way to repeat a swap
- * page within an mm (except in shmem, where it's the
- * shared object which takes the reference count)?
- * We believe SWAP_MAP_MAX cannot occur in Linux 2.4.
- *
- * If that's wrong, then we should worry more about
- * exit_mmap() and do_munmap() cases described above:
- * we might be resetting SWAP_MAP_MAX too early here.
- * We know "Undead"s can happen, they're okay, so don't
- * report them; but do report if we reset SWAP_MAP_MAX.
- */
- if (*swap_map == SWAP_MAP_MAX) {
- swap_list_lock();
- swap_device_lock(si);
- nr_swap_pages++;
- *swap_map = 1;
- swap_device_unlock(si);
- swap_list_unlock();
- reset_overflow = 1;
- }
-
- /*
- * If a reference remains (rare), we would like to leave
- * the page in the swap cache; but try_to_swap_out could
- * then re-duplicate the entry once we drop page lock,
- * so we might loop indefinitely; also, that page could
- * not be swapped out to other storage meanwhile. So:
- * delete from cache even if there's another reference,
- * after ensuring that the data has been saved to disk -
- * since if the reference remains (rarer), it will be
- * read from disk into another page. Splitting into two
- * pages would be incorrect if swap supported "shared
- * private" pages, but they are handled by tmpfs files.
- * Note shmem_unuse already deleted its from swap cache.
- */
- if ((*swap_map > 1) && PageDirty(page) && PageSwapCache(page)) {
- rw_swap_page(WRITE, page);
- lock_page(page);
- }
- if (PageSwapCache(page))
- delete_from_swap_cache(page);
-
- /*
- * So we could skip searching mms once swap count went
- * to 1, we did not mark any present ptes as dirty: must
- * mark page dirty so try_to_swap_out will preserve it.
- */
- SetPageDirty(page);
- UnlockPage(page);
- page_cache_release(page);
-
- /*
- * Make sure that we aren't completely killing
- * interactive performance. Interruptible check on
- * signal_pending() would be nice, but changes the spec?
- */
- if (current->need_resched)
- schedule();
- }
-
- mmput(start_mm);
- if (reset_overflow) {
- printk(KERN_WARNING "swapoff: cleared swap entry overflow\n");
- swap_overflow = 0;
- }
- return retval;
-}
-
-asmlinkage long sys_swapoff(const char * specialfile)
-{
- struct swap_info_struct * p = NULL;
- unsigned short *swap_map;
- struct nameidata nd;
- int i, type, prev;
- int err;
-
- if (!capable(CAP_SYS_ADMIN))
- return -EPERM;
-
- err = user_path_walk(specialfile, &nd);
- if (err)
- goto out;
-
- lock_kernel();
- prev = -1;
- swap_list_lock();
- for (type = swap_list.head; type >= 0; type = swap_info[type].next) {
- p = swap_info + type;
- if ((p->flags & SWP_WRITEOK) == SWP_WRITEOK) {
- if (p->swap_file == nd.dentry)
- break;
- }
- prev = type;
- }
- err = -EINVAL;
- if (type < 0) {
- swap_list_unlock();
- goto out_dput;
- }
-
- if (prev < 0) {
- swap_list.head = p->next;
- } else {
- swap_info[prev].next = p->next;
- }
- if (type == swap_list.next) {
- /* just pick something that's safe... */
- swap_list.next = swap_list.head;
- }
- nr_swap_pages -= p->pages;
- total_swap_pages -= p->pages;
- p->flags = SWP_USED;
- swap_list_unlock();
- unlock_kernel();
- err = try_to_unuse(type);
- lock_kernel();
- if (err) {
- /* re-insert swap space back into swap_list */
- swap_list_lock();
- for (prev = -1, i = swap_list.head; i >= 0; prev = i, i = swap_info[i].next)
- if (p->prio >= swap_info[i].prio)
- break;
- p->next = i;
- if (prev < 0)
- swap_list.head = swap_list.next = p - swap_info;
- else
- swap_info[prev].next = p - swap_info;
- nr_swap_pages += p->pages;
- total_swap_pages += p->pages;
- p->flags = SWP_WRITEOK;
- swap_list_unlock();
- goto out_dput;
- }
- if (p->swap_device)
- blkdev_put(p->swap_file->d_inode->i_bdev, BDEV_SWAP);
- path_release(&nd);
-
- swap_list_lock();
- swap_device_lock(p);
- nd.mnt = p->swap_vfsmnt;
- nd.dentry = p->swap_file;
- p->swap_vfsmnt = NULL;
- p->swap_file = NULL;
- p->swap_device = 0;
- p->max = 0;
- swap_map = p->swap_map;
- p->swap_map = NULL;
- p->flags = 0;
- swap_device_unlock(p);
- swap_list_unlock();
- vfree(swap_map);
- err = 0;
-
-out_dput:
- unlock_kernel();
- path_release(&nd);
-out:
- return err;
-}
-
-int get_swaparea_info(char *buf)
-{
- char * page = (char *) __get_free_page(GFP_KERNEL);
- struct swap_info_struct *ptr = swap_info;
- int i, j, len = 0, usedswap;
-
- if (!page)
- return -ENOMEM;
-
- len += sprintf(buf, "Filename\t\t\tType\t\tSize\tUsed\tPriority\n");
- for (i = 0 ; i < nr_swapfiles ; i++, ptr++) {
- if ((ptr->flags & SWP_USED) && ptr->swap_map) {
- char * path = d_path(ptr->swap_file, ptr->swap_vfsmnt,
- page, PAGE_SIZE);
-
- len += sprintf(buf + len, "%-31s ", path);
-
- if (!ptr->swap_device)
- len += sprintf(buf + len, "file\t\t");
- else
- len += sprintf(buf + len, "partition\t");
-
- usedswap = 0;
- for (j = 0; j < ptr->max; ++j)
- switch (ptr->swap_map[j]) {
- case SWAP_MAP_BAD:
- case 0:
- continue;
- default:
- usedswap++;
- }
- len += sprintf(buf + len, "%d\t%d\t%d\n", ptr->pages << (PAGE_SHIFT - 10),
- usedswap << (PAGE_SHIFT - 10), ptr->prio);
- }
- }
- free_page((unsigned long) page);
- return len;
-}
-
-int is_swap_partition(kdev_t dev) {
- struct swap_info_struct *ptr = swap_info;
- int i;
-
- for (i = 0 ; i < nr_swapfiles ; i++, ptr++) {
- if (ptr->flags & SWP_USED)
- if (ptr->swap_device == dev)
- return 1;
- }
- return 0;
-}
-
-/*
- * Written 01/25/92 by Simmule Turner, heavily changed by Linus.
- *
- * The swapon system call
- */
-asmlinkage long sys_swapon(const char * specialfile, int swap_flags)
-{
- struct swap_info_struct * p;
- struct nameidata nd;
- struct inode * swap_inode;
- unsigned int type;
- int i, j, prev;
- int error;
- static int least_priority = 0;
- union swap_header *swap_header = 0;
- int swap_header_version;
- int nr_good_pages = 0;
- unsigned long maxpages = 1;
- int swapfilesize;
- struct block_device *bdev = NULL;
- unsigned short *swap_map;
-
- if (!capable(CAP_SYS_ADMIN))
- return -EPERM;
- lock_kernel();
- swap_list_lock();
- p = swap_info;
- for (type = 0 ; type < nr_swapfiles ; type++,p++)
- if (!(p->flags & SWP_USED))
- break;
- error = -EPERM;
- if (type >= MAX_SWAPFILES) {
- swap_list_unlock();
- goto out;
- }
- if (type >= nr_swapfiles)
- nr_swapfiles = type+1;
- p->flags = SWP_USED;
- p->swap_file = NULL;
- p->swap_vfsmnt = NULL;
- p->swap_device = 0;
- p->swap_map = NULL;
- p->lowest_bit = 0;
- p->highest_bit = 0;
- p->cluster_nr = 0;
- p->sdev_lock = SPIN_LOCK_UNLOCKED;
- p->next = -1;
- if (swap_flags & SWAP_FLAG_PREFER) {
- p->prio =
- (swap_flags & SWAP_FLAG_PRIO_MASK)>>SWAP_FLAG_PRIO_SHIFT;
- } else {
- p->prio = --least_priority;
- }
- swap_list_unlock();
- error = user_path_walk(specialfile, &nd);
- if (error)
- goto bad_swap_2;
-
- p->swap_file = nd.dentry;
- p->swap_vfsmnt = nd.mnt;
- swap_inode = nd.dentry->d_inode;
- error = -EINVAL;
-
- if (S_ISBLK(swap_inode->i_mode)) {
- kdev_t dev = swap_inode->i_rdev;
- struct block_device_operations *bdops;
- devfs_handle_t de;
-
- p->swap_device = dev;
- set_blocksize(dev, PAGE_SIZE);
-
- bd_acquire(swap_inode);
- bdev = swap_inode->i_bdev;
- de = devfs_get_handle_from_inode(swap_inode);
- bdops = devfs_get_ops(de); /* Increments module use count */
- if (bdops) bdev->bd_op = bdops;
-
- error = blkdev_get(bdev, FMODE_READ|FMODE_WRITE, 0, BDEV_SWAP);
- devfs_put_ops(de);/*Decrement module use count now we're safe*/
- if (error)
- goto bad_swap_2;
- set_blocksize(dev, PAGE_SIZE);
- error = -ENODEV;
- if (!dev || (blk_size[MAJOR(dev)] &&
- !blk_size[MAJOR(dev)][MINOR(dev)]))
- goto bad_swap;
- swapfilesize = 0;
- if (blk_size[MAJOR(dev)])
- swapfilesize = blk_size[MAJOR(dev)][MINOR(dev)]
- >> (PAGE_SHIFT - 10);
- } else if (S_ISREG(swap_inode->i_mode))
- swapfilesize = swap_inode->i_size >> PAGE_SHIFT;
- else
- goto bad_swap;
-
- error = -EBUSY;
- for (i = 0 ; i < nr_swapfiles ; i++) {
- struct swap_info_struct *q = &swap_info[i];
- if (i == type || !q->swap_file)
- continue;
- if (swap_inode->i_mapping == q->swap_file->d_inode->i_mapping)
- goto bad_swap;
- }
-
- swap_header = (void *) __get_free_page(GFP_USER);
- if (!swap_header) {
- printk("Unable to start swapping: out of memory :-)\n");
- error = -ENOMEM;
- goto bad_swap;
- }
-
- lock_page(virt_to_page(swap_header));
- rw_swap_page_nolock(READ, SWP_ENTRY(type,0), (char *) swap_header);
-
- if (!memcmp("SWAP-SPACE",swap_header->magic.magic,10))
- swap_header_version = 1;
- else if (!memcmp("SWAPSPACE2",swap_header->magic.magic,10))
- swap_header_version = 2;
- else {
- printk("Unable to find swap-space signature\n");
- error = -EINVAL;
- goto bad_swap;
- }
-
- switch (swap_header_version) {
- case 1:
- memset(((char *) swap_header)+PAGE_SIZE-10,0,10);
- j = 0;
- p->lowest_bit = 0;
- p->highest_bit = 0;
- for (i = 1 ; i < 8*PAGE_SIZE ; i++) {
- if (test_bit(i,(char *) swap_header)) {
- if (!p->lowest_bit)
- p->lowest_bit = i;
- p->highest_bit = i;
- maxpages = i+1;
- j++;
- }
- }
- nr_good_pages = j;
- p->swap_map = vmalloc(maxpages * sizeof(short));
- if (!p->swap_map) {
- error = -ENOMEM;
- goto bad_swap;
- }
- for (i = 1 ; i < maxpages ; i++) {
- if (test_bit(i,(char *) swap_header))
- p->swap_map[i] = 0;
- else
- p->swap_map[i] = SWAP_MAP_BAD;
- }
- break;
-
- case 2:
- /* Check the swap header's sub-version and the size of
- the swap file and bad block lists */
- if (swap_header->info.version != 1) {
- printk(KERN_WARNING
- "Unable to handle swap header version %d\n",
- swap_header->info.version);
- error = -EINVAL;
- goto bad_swap;
- }
-
- p->lowest_bit = 1;
- maxpages = SWP_OFFSET(SWP_ENTRY(0,~0UL)) - 1;
- if (maxpages > swap_header->info.last_page)
- maxpages = swap_header->info.last_page;
- p->highest_bit = maxpages - 1;
-
- error = -EINVAL;
- if (swap_header->info.nr_badpages > MAX_SWAP_BADPAGES)
- goto bad_swap;
-
- /* OK, set up the swap map and apply the bad block list */
- if (!(p->swap_map = vmalloc(maxpages * sizeof(short)))) {
- error = -ENOMEM;
- goto bad_swap;
- }
-
- error = 0;
- memset(p->swap_map, 0, maxpages * sizeof(short));
- for (i=0; i<swap_header->info.nr_badpages; i++) {
- int page = swap_header->info.badpages[i];
- if (page <= 0 || page >= swap_header->info.last_page)
- error = -EINVAL;
- else
- p->swap_map[page] = SWAP_MAP_BAD;
- }
- nr_good_pages = swap_header->info.last_page -
- swap_header->info.nr_badpages -
- 1 /* header page */;
- if (error)
- goto bad_swap;
- }
-
- if (swapfilesize && maxpages > swapfilesize) {
- printk(KERN_WARNING
- "Swap area shorter than signature indicates\n");
- error = -EINVAL;
- goto bad_swap;
- }
- if (!nr_good_pages) {
- printk(KERN_WARNING "Empty swap-file\n");
- error = -EINVAL;
- goto bad_swap;
- }
- p->swap_map[0] = SWAP_MAP_BAD;
- swap_list_lock();
- swap_device_lock(p);
- p->max = maxpages;
- p->flags = SWP_WRITEOK;
- p->pages = nr_good_pages;
- nr_swap_pages += nr_good_pages;
- total_swap_pages += nr_good_pages;
- printk(KERN_INFO "Adding Swap: %dk swap-space (priority %d)\n",
- nr_good_pages<<(PAGE_SHIFT-10), p->prio);
-
- /* insert swap space into swap_list: */
- prev = -1;
- for (i = swap_list.head; i >= 0; i = swap_info[i].next) {
- if (p->prio >= swap_info[i].prio) {
- break;
- }
- prev = i;
- }
- p->next = i;
- if (prev < 0) {
- swap_list.head = swap_list.next = p - swap_info;
- } else {
- swap_info[prev].next = p - swap_info;
- }
- swap_device_unlock(p);
- swap_list_unlock();
- error = 0;
- goto out;
-bad_swap:
- if (bdev)
- blkdev_put(bdev, BDEV_SWAP);
-bad_swap_2:
- swap_list_lock();
- swap_map = p->swap_map;
- nd.mnt = p->swap_vfsmnt;
- nd.dentry = p->swap_file;
- p->swap_device = 0;
- p->swap_file = NULL;
- p->swap_vfsmnt = NULL;
- p->swap_map = NULL;
- p->flags = 0;
- if (!(swap_flags & SWAP_FLAG_PREFER))
- ++least_priority;
- swap_list_unlock();
- if (swap_map)
- vfree(swap_map);
- path_release(&nd);
-out:
- if (swap_header)
- free_page((long) swap_header);
- unlock_kernel();
- return error;
-}
-
-void si_swapinfo(struct sysinfo *val)
-{
- unsigned int i;
- unsigned long nr_to_be_unused = 0;
-
- swap_list_lock();
- for (i = 0; i < nr_swapfiles; i++) {
- unsigned int j;
- if (swap_info[i].flags != SWP_USED)
- continue;
- for (j = 0; j < swap_info[i].max; ++j) {
- switch (swap_info[i].swap_map[j]) {
- case 0:
- case SWAP_MAP_BAD:
- continue;
- default:
- nr_to_be_unused++;
- }
- }
- }
- val->freeswap = nr_swap_pages + nr_to_be_unused;
- val->totalswap = total_swap_pages + nr_to_be_unused;
- swap_list_unlock();
-}
-
-/*
- * Verify that a swap entry is valid and increment its swap map count.
- *
- * Note: if swap_map[] reaches SWAP_MAP_MAX the entries are treated as
- * "permanent", but will be reclaimed by the next swapoff.
- */
-int swap_duplicate(swp_entry_t entry)
-{
- struct swap_info_struct * p;
- unsigned long offset, type;
- int result = 0;
-
- type = SWP_TYPE(entry);
- if (type >= nr_swapfiles)
- goto bad_file;
- p = type + swap_info;
- offset = SWP_OFFSET(entry);
-
- swap_device_lock(p);
- if (offset < p->max && p->swap_map[offset]) {
- if (p->swap_map[offset] < SWAP_MAP_MAX - 1) {
- p->swap_map[offset]++;
- result = 1;
- } else if (p->swap_map[offset] <= SWAP_MAP_MAX) {
- if (swap_overflow++ < 5)
- printk(KERN_WARNING "swap_dup: swap entry overflow\n");
- p->swap_map[offset] = SWAP_MAP_MAX;
- result = 1;
- }
- }
- swap_device_unlock(p);
-out:
- return result;
-
-bad_file:
- printk(KERN_ERR "swap_dup: %s%08lx\n", Bad_file, entry.val);
- goto out;
-}
-
-/*
- * Prior swap_duplicate protects against swap device deletion.
- */
-void get_swaphandle_info(swp_entry_t entry, unsigned long *offset,
- kdev_t *dev, struct inode **swapf)
-{
- unsigned long type;
- struct swap_info_struct *p;
-
- type = SWP_TYPE(entry);
- if (type >= nr_swapfiles) {
- printk(KERN_ERR "rw_swap_page: %s%08lx\n", Bad_file, entry.val);
- return;
- }
-
- p = &swap_info[type];
- *offset = SWP_OFFSET(entry);
- if (*offset >= p->max && *offset != 0) {
- printk(KERN_ERR "rw_swap_page: %s%08lx\n", Bad_offset, entry.val);
- return;
- }
- if (p->swap_map && !p->swap_map[*offset]) {
- printk(KERN_ERR "rw_swap_page: %s%08lx\n", Unused_offset, entry.val);
- return;
- }
- if (!(p->flags & SWP_USED)) {
- printk(KERN_ERR "rw_swap_page: %s%08lx\n", Unused_file, entry.val);
- return;
- }
-
- if (p->swap_device) {
- *dev = p->swap_device;
- } else if (p->swap_file) {
- *swapf = p->swap_file->d_inode;
- } else {
- printk(KERN_ERR "rw_swap_page: no swap file or device\n");
- }
- return;
-}
-
-/*
- * swap_device_lock prevents swap_map being freed. Don't grab an extra
- * reference on the swaphandle, it doesn't matter if it becomes unused.
- */
-int valid_swaphandles(swp_entry_t entry, unsigned long *offset)
-{
- int ret = 0, i = 1 << page_cluster;
- unsigned long toff;
- struct swap_info_struct *swapdev = SWP_TYPE(entry) + swap_info;
-
- if (!page_cluster) /* no readahead */
- return 0;
- toff = (SWP_OFFSET(entry) >> page_cluster) << page_cluster;
- if (!toff) /* first page is swap header */
- toff++, i--;
- *offset = toff;
-
- swap_device_lock(swapdev);
- do {
- /* Don't read-ahead past the end of the swap area */
- if (toff >= swapdev->max)
- break;
- /* Don't read in free or bad pages */
- if (!swapdev->swap_map[toff])
- break;
- if (swapdev->swap_map[toff] == SWAP_MAP_BAD)
- break;
- toff++;
- ret++;
- } while (--i);
- swap_device_unlock(swapdev);
- return ret;
-}
--- /dev/null
+VERSION = 2
+PATCHLEVEL = 4
+SUBLEVEL = 21
+EXTRAVERSION = -xeno
+
+KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
+
+ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/)
+
+# Xeno hack XXX
+ARCH := xeno
+SUBARCH := i386
+
+KERNELPATH=kernel-$(shell echo $(KERNELRELEASE) | sed -e "s/-//g")
+
+CONFIG_SHELL := $(shell if [ -x "$$BASH" ]; then echo $$BASH; \
+ else if [ -x /bin/bash ]; then echo /bin/bash; \
+ else echo sh; fi ; fi)
+TOPDIR := $(shell /bin/pwd)
+
+HPATH = $(TOPDIR)/include
+FINDHPATH = $(HPATH)/asm $(HPATH)/linux $(HPATH)/scsi $(HPATH)/net $(HPATH)/math-emu
+
+HOSTCC = gcc
+HOSTCFLAGS = -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer
+
+CROSS_COMPILE =
+
+#
+# Include the make variables (CC, etc...)
+#
+
+AS = $(CROSS_COMPILE)as
+LD = $(CROSS_COMPILE)ld
+CC = $(CROSS_COMPILE)gcc
+CPP = $(CC) -E
+AR = $(CROSS_COMPILE)ar
+NM = $(CROSS_COMPILE)nm
+STRIP = $(CROSS_COMPILE)strip
+OBJCOPY = $(CROSS_COMPILE)objcopy
+OBJDUMP = $(CROSS_COMPILE)objdump
+MAKEFILES = $(TOPDIR)/.config
+GENKSYMS = /sbin/genksyms
+DEPMOD = /sbin/depmod
+MODFLAGS = -DMODULE
+CFLAGS_KERNEL =
+PERL = perl
+
+export VERSION PATCHLEVEL SUBLEVEL EXTRAVERSION KERNELRELEASE ARCH \
+ CONFIG_SHELL TOPDIR HPATH HOSTCC HOSTCFLAGS CROSS_COMPILE AS LD CC \
+ CPP AR NM STRIP OBJCOPY OBJDUMP MAKE MAKEFILES GENKSYMS MODFLAGS PERL
+
+all: do-it-all
+
+#
+# Make "config" the default target if there is no configuration file or
+# "depend" the target if there is no top-level dependency information.
+#
+
+ifeq (.config,$(wildcard .config))
+include .config
+ifeq (.depend,$(wildcard .depend))
+include .depend
+do-it-all: Version vmlinux
+else
+CONFIGURATION = depend
+do-it-all: depend
+endif
+else
+CONFIGURATION = config
+do-it-all: config
+endif
+
+#
+# INSTALL_PATH specifies where to place the updated kernel and system map
+# images. Uncomment if you want to place them anywhere other than root.
+#
+
+#export INSTALL_PATH=/boot
+
+#
+# INSTALL_MOD_PATH specifies a prefix to MODLIB for module directory
+# relocations required by build roots. This is not defined in the
+# makefile but the arguement can be passed to make if needed.
+#
+
+MODLIB := $(INSTALL_MOD_PATH)/lib/modules/$(KERNELRELEASE)
+export MODLIB
+
+#
+# standard CFLAGS
+#
+
+CPPFLAGS := -D__KERNEL__ -I$(HPATH)
+
+CFLAGS := $(CPPFLAGS) -Wall -Wstrict-prototypes -Wno-trigraphs -O2 \
+ -fno-strict-aliasing -fno-common
+ifndef CONFIG_FRAME_POINTER
+CFLAGS += -fomit-frame-pointer
+endif
+AFLAGS := -D__ASSEMBLY__ $(CPPFLAGS)
+
+#
+# ROOT_DEV specifies the default root-device when making the image.
+# This can be either FLOPPY, CURRENT, /dev/xxxx or empty, in which case
+# the default of FLOPPY is used by 'build'.
+# This is i386 specific.
+#
+
+export ROOT_DEV = CURRENT
+
+#
+# If you want to preset the SVGA mode, uncomment the next line and
+# set SVGA_MODE to whatever number you want.
+# Set it to -DSVGA_MODE=NORMAL_VGA if you just want the EGA/VGA mode.
+# The number is the same as you would ordinarily press at bootup.
+# This is i386 specific.
+#
+
+export SVGA_MODE = -DSVGA_MODE=NORMAL_VGA
+
+#
+# If you want the RAM disk device, define this to be the size in blocks.
+# This is i386 specific.
+#
+
+#export RAMDISK = -DRAMDISK=512
+
+CORE_FILES =kernel/kernel.o mm/mm.o fs/fs.o ipc/ipc.o
+NETWORKS =net/network.o
+
+LIBS =$(TOPDIR)/lib/lib.a
+SUBDIRS =kernel drivers mm fs net ipc lib
+
+DRIVERS-n :=
+DRIVERS-y :=
+DRIVERS-m :=
+DRIVERS- :=
+
+DRIVERS-$(CONFIG_ACPI) += drivers/acpi/acpi.o
+DRIVERS-$(CONFIG_PARPORT) += drivers/parport/driver.o
+DRIVERS-y += drivers/char/char.o \
+ drivers/block/block.o \
+ drivers/misc/misc.o \
+ drivers/net/net.o
+DRIVERS-$(CONFIG_AGP) += drivers/char/agp/agp.o
+DRIVERS-$(CONFIG_DRM_NEW) += drivers/char/drm/drm.o
+DRIVERS-$(CONFIG_DRM_OLD) += drivers/char/drm-4.0/drm.o
+DRIVERS-$(CONFIG_NUBUS) += drivers/nubus/nubus.a
+DRIVERS-$(CONFIG_NET_FC) += drivers/net/fc/fc.o
+DRIVERS-$(CONFIG_DEV_APPLETALK) += drivers/net/appletalk/appletalk.o
+DRIVERS-$(CONFIG_TR) += drivers/net/tokenring/tr.o
+DRIVERS-$(CONFIG_WAN) += drivers/net/wan/wan.o
+DRIVERS-$(CONFIG_ARCNET) += drivers/net/arcnet/arcnetdrv.o
+DRIVERS-$(CONFIG_ATM) += drivers/atm/atm.o
+DRIVERS-$(CONFIG_IDE) += drivers/ide/idedriver.o
+DRIVERS-$(CONFIG_FC4) += drivers/fc4/fc4.a
+DRIVERS-$(CONFIG_SCSI) += drivers/scsi/scsidrv.o
+DRIVERS-$(CONFIG_FUSION_BOOT) += drivers/message/fusion/fusion.o
+DRIVERS-$(CONFIG_IEEE1394) += drivers/ieee1394/ieee1394drv.o
+
+ifneq ($(CONFIG_CD_NO_IDESCSI)$(CONFIG_BLK_DEV_IDECD)$(CONFIG_BLK_DEV_SR)$(CONFIG_PARIDE_PCD),)
+DRIVERS-y += drivers/cdrom/driver.o
+endif
+
+DRIVERS-$(CONFIG_SOUND) += drivers/sound/sounddrivers.o
+DRIVERS-$(CONFIG_PCI) += drivers/pci/driver.o
+DRIVERS-$(CONFIG_MTD) += drivers/mtd/mtdlink.o
+DRIVERS-$(CONFIG_PCMCIA) += drivers/pcmcia/pcmcia.o
+DRIVERS-$(CONFIG_NET_PCMCIA) += drivers/net/pcmcia/pcmcia_net.o
+DRIVERS-$(CONFIG_NET_WIRELESS) += drivers/net/wireless/wireless_net.o
+DRIVERS-$(CONFIG_PCMCIA_CHRDEV) += drivers/char/pcmcia/pcmcia_char.o
+DRIVERS-$(CONFIG_DIO) += drivers/dio/dio.a
+DRIVERS-$(CONFIG_SBUS) += drivers/sbus/sbus_all.o
+DRIVERS-$(CONFIG_ZORRO) += drivers/zorro/driver.o
+DRIVERS-$(CONFIG_FC4) += drivers/fc4/fc4.a
+DRIVERS-$(CONFIG_PPC32) += drivers/macintosh/macintosh.o
+DRIVERS-$(CONFIG_MAC) += drivers/macintosh/macintosh.o
+DRIVERS-$(CONFIG_ISAPNP) += drivers/pnp/pnp.o
+DRIVERS-$(CONFIG_SGI_IP22) += drivers/sgi/sgi.a
+DRIVERS-$(CONFIG_VT) += drivers/video/video.o
+DRIVERS-$(CONFIG_PARIDE) += drivers/block/paride/paride.a
+DRIVERS-$(CONFIG_HAMRADIO) += drivers/net/hamradio/hamradio.o
+DRIVERS-$(CONFIG_TC) += drivers/tc/tc.a
+DRIVERS-$(CONFIG_USB) += drivers/usb/usbdrv.o
+DRIVERS-y +=drivers/media/media.o
+DRIVERS-$(CONFIG_INPUT) += drivers/input/inputdrv.o
+DRIVERS-$(CONFIG_HIL) += drivers/hil/hil.o
+DRIVERS-$(CONFIG_I2O) += drivers/message/i2o/i2o.o
+DRIVERS-$(CONFIG_IRDA) += drivers/net/irda/irda.o
+DRIVERS-$(CONFIG_I2C) += drivers/i2c/i2c.o
+DRIVERS-$(CONFIG_PHONE) += drivers/telephony/telephony.o
+DRIVERS-$(CONFIG_MD) += drivers/md/mddev.o
+DRIVERS-$(CONFIG_GSC) += drivers/gsc/gscbus.o
+DRIVERS-$(CONFIG_BLUEZ) += drivers/bluetooth/bluetooth.o
+DRIVERS-$(CONFIG_HOTPLUG_PCI) += drivers/hotplug/vmlinux-obj.o
+DRIVERS-$(CONFIG_ISDN_BOOL) += drivers/isdn/vmlinux-obj.o
+
+DRIVERS := $(DRIVERS-y)
+
+
+# files removed with 'make clean'
+CLEAN_FILES = \
+ kernel/ksyms.lst include/linux/compile.h \
+ vmlinux System.map \
+ .tmp* \
+ drivers/char/consolemap_deftbl.c drivers/video/promcon_tbl.c \
+ drivers/char/conmakehash \
+ drivers/char/drm/*-mod.c \
+ drivers/pci/devlist.h drivers/pci/classlist.h drivers/pci/gen-devlist \
+ drivers/zorro/devlist.h drivers/zorro/gen-devlist \
+ drivers/sound/bin2hex drivers/sound/hex2hex \
+ drivers/atm/fore200e_mkfirm drivers/atm/{pca,sba}*{.bin,.bin1,.bin2} \
+ drivers/scsi/aic7xxx/aicasm/aicasm \
+ drivers/scsi/aic7xxx/aicasm/aicasm_gram.c \
+ drivers/scsi/aic7xxx/aicasm/aicasm_gram.h \
+ drivers/scsi/aic7xxx/aicasm/aicasm_macro_gram.c \
+ drivers/scsi/aic7xxx/aicasm/aicasm_macro_gram.h \
+ drivers/scsi/aic7xxx/aicasm/aicasm_macro_scan.c \
+ drivers/scsi/aic7xxx/aicasm/aicasm_scan.c \
+ drivers/scsi/aic7xxx/aicasm/aicdb.h \
+ drivers/scsi/aic7xxx/aicasm/y.tab.h \
+ drivers/scsi/53c700_d.h \
+ net/khttpd/make_times_h \
+ net/khttpd/times.h \
+ submenu*
+# directories removed with 'make clean'
+CLEAN_DIRS = \
+ modules
+
+# files removed with 'make mrproper'
+MRPROPER_FILES = \
+ include/linux/autoconf.h include/linux/version.h \
+ drivers/net/hamradio/soundmodem/sm_tbl_{afsk1200,afsk2666,fsk9600}.h \
+ drivers/net/hamradio/soundmodem/sm_tbl_{hapn4800,psk4800}.h \
+ drivers/net/hamradio/soundmodem/sm_tbl_{afsk2400_7,afsk2400_8}.h \
+ drivers/net/hamradio/soundmodem/gentbl \
+ drivers/sound/*_boot.h drivers/sound/.*.boot \
+ drivers/sound/msndinit.c \
+ drivers/sound/msndperm.c \
+ drivers/sound/pndsperm.c \
+ drivers/sound/pndspini.c \
+ drivers/atm/fore200e_*_fw.c drivers/atm/.fore200e_*.fw \
+ .version .config* config.in config.old \
+ scripts/tkparse scripts/kconfig.tk scripts/kconfig.tmp \
+ scripts/lxdialog/*.o scripts/lxdialog/lxdialog \
+ .menuconfig.log \
+ include/asm \
+ .hdepend scripts/mkdep scripts/split-include scripts/docproc \
+ $(TOPDIR)/include/linux/modversions.h \
+ kernel.spec
+
+# directories removed with 'make mrproper'
+MRPROPER_DIRS = \
+ include/config \
+ $(TOPDIR)/include/linux/modules
+
+
+include arch/$(ARCH)/Makefile
+
+# Extra cflags for kbuild 2.4. The default is to forbid includes by kernel code
+# from user space headers. Some UML code requires user space headers, in the
+# UML Makefiles add 'kbuild_2_4_nostdinc :=' before include Rules.make. No
+# other kernel code should include user space headers, if you need
+# 'kbuild_2_4_nostdinc :=' or -I/usr/include for kernel code and you are not UML
+# then your code is broken! KAO.
+
+kbuild_2_4_nostdinc := -nostdinc -iwithprefix include
+export kbuild_2_4_nostdinc
+
+export CPPFLAGS CFLAGS CFLAGS_KERNEL AFLAGS AFLAGS_KERNEL
+
+export NETWORKS DRIVERS LIBS HEAD LDFLAGS LINKFLAGS MAKEBOOT ASFLAGS
+
+.S.s:
+ $(CPP) $(AFLAGS) $(AFLAGS_KERNEL) -traditional -o $*.s $<
+.S.o:
+ $(CC) $(AFLAGS) $(AFLAGS_KERNEL) -traditional -c -o $*.o $<
+
+Version: dummy
+ @rm -f include/linux/compile.h
+
+boot: vmlinux
+ @$(MAKE) CFLAGS="$(CFLAGS) $(CFLAGS_KERNEL)" -C arch/$(ARCH)/boot
+
+vmlinux: include/linux/version.h $(CONFIGURATION) init/main.o init/version.o init/do_mounts.o linuxsubdirs
+ $(LD) $(LINKFLAGS) $(HEAD) init/main.o init/version.o init/do_mounts.o \
+ --start-group \
+ $(CORE_FILES) \
+ $(DRIVERS) \
+ $(NETWORKS) \
+ $(LIBS) \
+ --end-group \
+ -o vmlinux
+ $(NM) vmlinux | grep -v '\(compiled\)\|\(\.o$$\)\|\( [aUw] \)\|\(\.\.ng$$\)\|\(LASH[RL]DI\)' | sort > System.map
+
+symlinks:
+ rm -f include/asm
+ ( cd include ; ln -sf asm-$(ARCH) asm)
+ @if [ ! -d include/linux/modules ]; then \
+ mkdir include/linux/modules; \
+ fi
+
+oldconfig: symlinks
+ $(CONFIG_SHELL) scripts/Configure -d arch/$(ARCH)/config.in
+
+xconfig: symlinks
+ $(MAKE) -C scripts kconfig.tk
+ wish -f scripts/kconfig.tk
+
+menuconfig: include/linux/version.h symlinks
+ $(MAKE) -C scripts/lxdialog all
+ $(CONFIG_SHELL) scripts/Menuconfig arch/$(ARCH)/config.in
+
+config: symlinks
+ $(CONFIG_SHELL) scripts/Configure arch/$(ARCH)/config.in
+
+include/config/MARKER: scripts/split-include include/linux/autoconf.h
+ scripts/split-include include/linux/autoconf.h include/config
+ @ touch include/config/MARKER
+
+linuxsubdirs: $(patsubst %, _dir_%, $(SUBDIRS))
+
+$(patsubst %, _dir_%, $(SUBDIRS)) : dummy include/linux/version.h include/config/MARKER
+ $(MAKE) CFLAGS="$(CFLAGS) $(CFLAGS_KERNEL)" -C $(patsubst _dir_%, %, $@)
+
+$(TOPDIR)/include/linux/version.h: include/linux/version.h
+$(TOPDIR)/include/linux/compile.h: include/linux/compile.h
+
+newversion:
+ . scripts/mkversion > .tmpversion
+ @mv -f .tmpversion .version
+
+uts_len := 64
+uts_truncate := sed -e 's/\(.\{1,$(uts_len)\}\).*/\1/'
+
+include/linux/compile.h: $(CONFIGURATION) include/linux/version.h newversion
+ @echo -n \#`cat .version` > .ver1
+ @if [ -n "$(CONFIG_SMP)" ] ; then echo -n " SMP" >> .ver1; fi
+ @if [ -f .name ]; then echo -n \-`cat .name` >> .ver1; fi
+ @LANG=C echo ' '`date` >> .ver1
+ @echo \#define UTS_VERSION \"`cat .ver1 | $(uts_truncate)`\" > .ver
+ @LANG=C echo \#define LINUX_COMPILE_TIME \"`date +%T`\" >> .ver
+ @echo \#define LINUX_COMPILE_BY \"`whoami`\" >> .ver
+ @echo \#define LINUX_COMPILE_HOST \"`hostname | $(uts_truncate)`\" >> .ver
+ @([ -x /bin/dnsdomainname ] && /bin/dnsdomainname > .ver1) || \
+ ([ -x /bin/domainname ] && /bin/domainname > .ver1) || \
+ echo > .ver1
+ @echo \#define LINUX_COMPILE_DOMAIN \"`cat .ver1 | $(uts_truncate)`\" >> .ver
+ @echo \#define LINUX_COMPILER \"`$(CC) $(CFLAGS) -v 2>&1 | tail -n 1`\" >> .ver
+ @mv -f .ver $@
+ @rm -f .ver1
+
+include/linux/version.h: ./Makefile
+ @expr length "$(KERNELRELEASE)" \<= $(uts_len) > /dev/null || \
+ (echo KERNELRELEASE \"$(KERNELRELEASE)\" exceeds $(uts_len) characters >&2; false)
+ @echo \#define UTS_RELEASE \"$(KERNELRELEASE)\" > .ver
+ @echo \#define LINUX_VERSION_CODE `expr $(VERSION) \\* 65536 + $(PATCHLEVEL) \\* 256 + $(SUBLEVEL)` >> .ver
+ @echo '#define KERNEL_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c))' >>.ver
+ @mv -f .ver $@
+
+comma := ,
+
+init/version.o: init/version.c include/linux/compile.h include/config/MARKER
+ $(CC) $(CFLAGS) $(CFLAGS_KERNEL) -DUTS_MACHINE='"$(SUBARCH)"' -DKBUILD_BASENAME=$(subst $(comma),_,$(subst -,_,$(*F))) -c -o init/version.o init/version.c
+
+init/main.o: init/main.c include/config/MARKER
+ $(CC) $(CFLAGS) $(CFLAGS_KERNEL) $(PROFILING) -DKBUILD_BASENAME=$(subst $(comma),_,$(subst -,_,$(*F))) -c -o $@ $<
+
+init/do_mounts.o: init/do_mounts.c include/config/MARKER
+ $(CC) $(CFLAGS) $(CFLAGS_KERNEL) $(PROFILING) -DKBUILD_BASENAME=$(subst $(comma),_,$(subst -,_,$(*F))) -c -o $@ $<
+
+fs lib mm ipc kernel drivers net: dummy
+ $(MAKE) CFLAGS="$(CFLAGS) $(CFLAGS_KERNEL)" $(subst $@, _dir_$@, $@)
+
+TAGS: dummy
+ { find include/asm-${ARCH} -name '*.h' -print ; \
+ find include -type d \( -name "asm-*" -o -name config \) -prune -o -name '*.h' -print ; \
+ find $(SUBDIRS) init arch/${ARCH} -name '*.[chS]' ; } | grep -v SCCS | grep -v '\.svn' | etags -
+
+# Exuberant ctags works better with -I
+tags: dummy
+ CTAGSF=`ctags --version | grep -i exuberant >/dev/null && echo "-I __initdata,__exitdata,EXPORT_SYMBOL,EXPORT_SYMBOL_NOVERS"`; \
+ ctags $$CTAGSF `find include/asm-$(ARCH) -name '*.h'` && \
+ find include -type d \( -name "asm-*" -o -name config \) -prune -o -name '*.h' -print | xargs ctags $$CTAGSF -a && \
+ find $(SUBDIRS) init -name '*.[ch]' | xargs ctags $$CTAGSF -a
+
+ifdef CONFIG_MODULES
+ifdef CONFIG_MODVERSIONS
+MODFLAGS += -DMODVERSIONS -include $(HPATH)/linux/modversions.h
+endif
+
+.PHONY: modules
+modules: $(patsubst %, _mod_%, $(SUBDIRS))
+
+.PHONY: $(patsubst %, _mod_%, $(SUBDIRS))
+$(patsubst %, _mod_%, $(SUBDIRS)) : include/linux/version.h include/config/MARKER
+ $(MAKE) -C $(patsubst _mod_%, %, $@) CFLAGS="$(CFLAGS) $(MODFLAGS)" MAKING_MODULES=1 modules
+
+.PHONY: modules_install
+modules_install: _modinst_ $(patsubst %, _modinst_%, $(SUBDIRS)) _modinst_post
+
+.PHONY: _modinst_
+_modinst_:
+ @rm -rf $(MODLIB)/kernel
+ @rm -f $(MODLIB)/build
+ @mkdir -p $(MODLIB)/kernel
+ @ln -s $(TOPDIR) $(MODLIB)/build
+
+# If System.map exists, run depmod. This deliberately does not have a
+# dependency on System.map since that would run the dependency tree on
+# vmlinux. This depmod is only for convenience to give the initial
+# boot a modules.dep even before / is mounted read-write. However the
+# boot script depmod is the master version.
+ifeq "$(strip $(INSTALL_MOD_PATH))" ""
+depmod_opts :=
+else
+depmod_opts := -b $(INSTALL_MOD_PATH) -r
+endif
+.PHONY: _modinst_post
+_modinst_post: _modinst_post_pcmcia
+# if [ -r System.map ]; then $(DEPMOD) -ae -F System.map $(depmod_opts) $(KERNELRELEASE); fi
+
+# Backwards compatibilty symlinks for people still using old versions
+# of pcmcia-cs with hard coded pathnames on insmod. Remove
+# _modinst_post_pcmcia for kernel 2.4.1.
+.PHONY: _modinst_post_pcmcia
+_modinst_post_pcmcia:
+ cd $(MODLIB); \
+ mkdir -p pcmcia; \
+ find kernel -path '*/pcmcia/*' -name '*.o' | xargs -i -r ln -sf ../{} pcmcia
+
+.PHONY: $(patsubst %, _modinst_%, $(SUBDIRS))
+$(patsubst %, _modinst_%, $(SUBDIRS)) :
+ $(MAKE) -C $(patsubst _modinst_%, %, $@) modules_install
+
+# modules disabled....
+
+else
+modules modules_install: dummy
+ @echo
+ @echo "The present kernel configuration has modules disabled."
+ @echo "Type 'make config' and enable loadable module support."
+ @echo "Then build a kernel with module support enabled."
+ @echo
+ @exit 1
+endif
+
+clean: archclean
+ find . \( -name '*.[oas]' -o -name core -o -name '.*.flags' \) -type f -print \
+ | grep -v lxdialog/ | xargs rm -f
+ rm -f $(CLEAN_FILES)
+ rm -rf $(CLEAN_DIRS)
+ $(MAKE) -C Documentation/DocBook clean
+
+mrproper: clean archmrproper
+ find . \( -size 0 -o -name .depend \) -type f -print | xargs rm -f
+ rm -f $(MRPROPER_FILES)
+ rm -rf $(MRPROPER_DIRS)
+ $(MAKE) -C Documentation/DocBook mrproper
+
+distclean: mrproper
+ rm -f core `find . \( -not -type d \) -and \
+ \( -name '*.orig' -o -name '*.rej' -o -name '*~' \
+ -o -name '*.bak' -o -name '#*#' -o -name '.*.orig' \
+ -o -name '.*.rej' -o -name '.SUMS' -o -size 0 \) -type f -print` TAGS tags
+
+backup: mrproper
+ cd .. && tar cf - linux/ | gzip -9 > backup.gz
+ sync
+
+sgmldocs:
+ chmod 755 $(TOPDIR)/scripts/docgen
+ chmod 755 $(TOPDIR)/scripts/gen-all-syms
+ chmod 755 $(TOPDIR)/scripts/kernel-doc
+ $(MAKE) -C $(TOPDIR)/Documentation/DocBook books
+
+psdocs: sgmldocs
+ $(MAKE) -C Documentation/DocBook ps
+
+pdfdocs: sgmldocs
+ $(MAKE) -C Documentation/DocBook pdf
+
+htmldocs: sgmldocs
+ $(MAKE) -C Documentation/DocBook html
+
+mandocs:
+ chmod 755 $(TOPDIR)/scripts/kernel-doc
+ chmod 755 $(TOPDIR)/scripts/split-man
+ $(MAKE) -C Documentation/DocBook man
+
+sums:
+ find . -type f -print | sort | xargs sum > .SUMS
+
+dep-files: scripts/mkdep archdep include/linux/version.h
+ rm -f .depend .hdepend
+ $(MAKE) $(patsubst %,_sfdep_%,$(SUBDIRS)) _FASTDEP_ALL_SUB_DIRS="$(SUBDIRS)"
+ifdef CONFIG_MODVERSIONS
+ $(MAKE) update-modverfile
+endif
+ scripts/mkdep -- `find $(FINDHPATH) \( -name SCCS -o -name .svn \) -prune -o -follow -name \*.h ! -name modversions.h -print` > .hdepend
+ scripts/mkdep -- init/*.c > .depend
+
+ifdef CONFIG_MODVERSIONS
+MODVERFILE := $(TOPDIR)/include/linux/modversions.h
+else
+MODVERFILE :=
+endif
+export MODVERFILE
+
+depend dep: dep-files
+
+checkconfig:
+ find * -name '*.[hcS]' -type f -print | sort | xargs $(PERL) -w scripts/checkconfig.pl
+
+checkhelp:
+ find * -name [cC]onfig.in -print | sort | xargs $(PERL) -w scripts/checkhelp.pl
+
+checkincludes:
+ find * -name '*.[hcS]' -type f -print | sort | xargs $(PERL) -w scripts/checkincludes.pl
+
+ifdef CONFIGURATION
+..$(CONFIGURATION):
+ @echo
+ @echo "You have a bad or nonexistent" .$(CONFIGURATION) ": running 'make" $(CONFIGURATION)"'"
+ @echo
+ $(MAKE) $(CONFIGURATION)
+ @echo
+ @echo "Successful. Try re-making (ignore the error that follows)"
+ @echo
+ exit 1
+
+#dummy: ..$(CONFIGURATION)
+dummy:
+
+else
+
+dummy:
+
+endif
+
+include Rules.make
+
+#
+# This generates dependencies for the .h files.
+#
+
+scripts/mkdep: scripts/mkdep.c
+ $(HOSTCC) $(HOSTCFLAGS) -o scripts/mkdep scripts/mkdep.c
+
+scripts/split-include: scripts/split-include.c
+ $(HOSTCC) $(HOSTCFLAGS) -o scripts/split-include scripts/split-include.c
+
+#
+# RPM target
+#
+# If you do a make spec before packing the tarball you can rpm -ta it
+#
+spec:
+ . scripts/mkspec >kernel.spec
+
+#
+# Build a tar ball, generate an rpm from it and pack the result
+# There arw two bits of magic here
+# 1) The use of /. to avoid tar packing just the symlink
+# 2) Removing the .dep files as they have source paths in them that
+# will become invalid
+#
+rpm: clean spec
+ find . \( -size 0 -o -name .depend -o -name .hdepend \) -type f -print | xargs rm -f
+ set -e; \
+ cd $(TOPDIR)/.. ; \
+ ln -sf $(TOPDIR) $(KERNELPATH) ; \
+ tar -cvz --exclude CVS -f $(KERNELPATH).tar.gz $(KERNELPATH)/. ; \
+ rm $(KERNELPATH) ; \
+ cd $(TOPDIR) ; \
+ . scripts/mkversion > .version ; \
+ rpm -ta $(TOPDIR)/../$(KERNELPATH).tar.gz ; \
+ rm $(TOPDIR)/../$(KERNELPATH).tar.gz
--- /dev/null
+#
+# xeno/Makefile
+#
+# This file is included by the global makefile so that you can add your own
+# architecture-specific flags and dependencies. Remember to do have actions
+# for "archclean" and "archdep" for cleaning up and making dependencies for
+# this architecture
+#
+# This file is subject to the terms and conditions of the GNU General Public
+# License. See the file "COPYING" in the main directory of this archive
+# for more details.
+#
+# Copyright (C) 1994 by Linus Torvalds
+#
+# 19990713 Artur Skawina <skawina@geocities.com>
+# Added '-march' and '-mpreferred-stack-boundary' support
+#
+
+LD=$(CROSS_COMPILE)ld -m elf_i386
+OBJCOPY=$(CROSS_COMPILE)objcopy -O binary -R .note -R .comment -S
+LDFLAGS=-e stext
+LINKFLAGS =-T $(TOPDIR)/arch/xeno/vmlinux.lds $(LDFLAGS)
+
+CFLAGS += -pipe
+
+check_gcc = $(shell if $(CC) $(1) -S -o /dev/null -xc /dev/null > /dev/null 2>&1; then echo "$(1)"; else echo "$(2)"; fi)
+
+# prevent gcc from keeping the stack 16 byte aligned
+CFLAGS += $(call check_gcc,-mpreferred-stack-boundary=2,)
+
+ifdef CONFIG_M686
+CFLAGS += -march=i686
+endif
+
+ifdef CONFIG_MPENTIUMIII
+CFLAGS += -march=i686
+endif
+
+ifdef CONFIG_MPENTIUM4
+CFLAGS += -march=i686
+endif
+
+ifdef CONFIG_MK7
+CFLAGS += $(call check_gcc,-march=athlon,-march=i686 -malign-functions=4)
+endif
+
+HEAD := arch/xeno/kernel/head.o arch/xeno/kernel/init_task.o
+
+SUBDIRS += arch/xeno/kernel arch/xeno/mm arch/xeno/lib
+SUBDIRS += arch/xeno/drivers/console arch/xeno/drivers/network
+SUBDIRS += arch/xeno/drivers/dom0 arch/xeno/drivers/block
+SUBDIRS += arch/xeno/drivers/balloon
+
+CORE_FILES += arch/xeno/kernel/kernel.o arch/xeno/mm/mm.o
+CORE_FILES += arch/xeno/drivers/console/con.o
+CORE_FILES += arch/xeno/drivers/block/blk.o
+CORE_FILES += arch/xeno/drivers/network/net.o
+CORE_FILES += arch/xeno/drivers/dom0/dom0.o
+CORE_FILES += arch/xeno/drivers/balloon/balloon_driver.o
+LIBS := $(TOPDIR)/arch/xeno/lib/lib.a $(LIBS) $(TOPDIR)/arch/xeno/lib/lib.a
+
+arch/xeno/kernel: dummy
+ $(MAKE) linuxsubdirs SUBDIRS=arch/xeno/kernel
+
+arch/xeno/mm: dummy
+ $(MAKE) linuxsubdirs SUBDIRS=arch/xeno/mm
+
+arch/xeno/drivers/console: dummy
+ $(MAKE) linuxsubdirs SUBDIRS=arch/xeno/drivers/console
+
+arch/xeno/drivers/network: dummy
+ $(MAKE) linuxsubdirs SUBDIRS=arch/xeno/drivers/network
+
+arch/xeno/drivers/block: dummy
+ $(MAKE) linuxsubdirs SUBDIRS=arch/xeno/drivers/block
+
+arch/xeno/drivers/dom0: dummy
+ $(MAKE) linuxsubdirs SUBDIRS=arch/xeno/drivers/dom0
+
+arch/xeno/drivers/balloon: dummy
+ $(MAKE) linuxsubdirs SUBDIRS=arch/xeno/drivers/balloon
+
+MAKEBOOT = $(MAKE) -C arch/$(ARCH)/boot
+
+vmlinux: arch/xeno/vmlinux.lds
+
+FORCE: ;
+
+.PHONY: bzImage compressed clean archclean archmrproper archdep
+
+bzImage: vmlinux
+ @$(MAKEBOOT) image.gz
+
+install: bzImage
+ cp -a arch/$(ARCH)/boot/image.gz ../install/boot/xenolinux.gz
+
+archclean:
+ @$(MAKEBOOT) clean
+
+archmrproper:
+
+archdep:
+ @$(MAKEBOOT) dep
--- /dev/null
+#
+# arch/xeno/boot/Makefile
+#
+
+image.gz: image
+ gzip -f -9 < $< > $@
+
+image: $(TOPDIR)/vmlinux
+ # Guest OS header -- first 8 bytes are identifier 'XenoGues'.
+ echo -e -n 'XenoGues' >$@
+ # Guest OS header -- next 4 bytes are load address (0xC0000000).
+ echo -e -n '\000\000\000\300' >>$@
+ $(OBJCOPY) $< image.body
+ # Guest OS header is immediately followed by raw OS image.
+ # Start address must be at byte 0.
+ cat image.body >>$@
+ rm -f image.body
+
+dep:
+
+clean:
+ rm -f image image.gz
--- /dev/null
+#
+# For a description of the syntax of this configuration file,
+# see Documentation/kbuild/config-language.txt.
+#
+mainmenu_name "Linux Kernel Configuration"
+
+define_bool CONFIG_XENO y
+
+define_bool CONFIG_X86 y
+define_bool CONFIG_ISA y
+define_bool CONFIG_SBUS n
+
+define_bool CONFIG_UID16 y
+
+mainmenu_option next_comment
+comment 'Code maturity level options'
+bool 'Prompt for development and/or incomplete code/drivers' CONFIG_EXPERIMENTAL
+endmenu
+
+mainmenu_option next_comment
+comment 'Loadable module support'
+bool 'Enable loadable module support' CONFIG_MODULES
+if [ "$CONFIG_MODULES" = "y" ]; then
+ bool ' Set version information on all module symbols' CONFIG_MODVERSIONS
+ bool ' Kernel module loader' CONFIG_KMOD
+fi
+endmenu
+
+mainmenu_option next_comment
+comment 'Processor type and features'
+choice 'Processor family' \
+ "Pentium-Pro/Celeron/Pentium-II CONFIG_M686 \
+ Pentium-III/Celeron(Coppermine) CONFIG_MPENTIUMIII \
+ Pentium-4 CONFIG_MPENTIUM4 \
+ Athlon/Duron/K7 CONFIG_MK7" Pentium-Pro
+
+ define_bool CONFIG_X86_WP_WORKS_OK y
+ define_bool CONFIG_X86_INVLPG y
+ define_bool CONFIG_X86_CMPXCHG y
+ define_bool CONFIG_X86_XADD y
+ define_bool CONFIG_X86_BSWAP y
+ define_bool CONFIG_X86_POPAD_OK y
+ define_bool CONFIG_RWSEM_GENERIC_SPINLOCK n
+ define_bool CONFIG_RWSEM_XCHGADD_ALGORITHM y
+
+ define_bool CONFIG_X86_GOOD_APIC y
+ define_bool CONFIG_X86_PGE y
+ define_bool CONFIG_X86_USE_PPRO_CHECKSUM y
+ define_bool CONFIG_X86_TSC y
+
+if [ "$CONFIG_M686" = "y" ]; then
+ define_int CONFIG_X86_L1_CACHE_SHIFT 5
+fi
+if [ "$CONFIG_MPENTIUMIII" = "y" ]; then
+ define_int CONFIG_X86_L1_CACHE_SHIFT 5
+fi
+if [ "$CONFIG_MPENTIUM4" = "y" ]; then
+ define_int CONFIG_X86_L1_CACHE_SHIFT 7
+fi
+if [ "$CONFIG_MK7" = "y" ]; then
+ define_int CONFIG_X86_L1_CACHE_SHIFT 6
+ define_bool CONFIG_X86_USE_3DNOW y
+fi
+
+choice 'High Memory Support' \
+ "off CONFIG_NOHIGHMEM \
+ 4GB CONFIG_HIGHMEM4G \
+ 64GB CONFIG_HIGHMEM64G" off
+if [ "$CONFIG_HIGHMEM4G" = "y" ]; then
+ define_bool CONFIG_HIGHMEM y
+fi
+if [ "$CONFIG_HIGHMEM64G" = "y" ]; then
+ define_bool CONFIG_HIGHMEM y
+ define_bool CONFIG_X86_PAE y
+fi
+
+#bool 'Symmetric multi-processing support' CONFIG_SMP
+#if [ "$CONFIG_SMP" = "y" -a "$CONFIG_X86_CMPXCHG" = "y" ]; then
+# define_bool CONFIG_HAVE_DEC_LOCK y
+#fi
+endmenu
+
+mainmenu_option next_comment
+comment 'General setup'
+
+bool 'Networking support' CONFIG_NET
+
+bool 'System V IPC' CONFIG_SYSVIPC
+bool 'BSD Process Accounting' CONFIG_BSD_PROCESS_ACCT
+bool 'Sysctl support' CONFIG_SYSCTL
+if [ "$CONFIG_PROC_FS" = "y" ]; then
+ choice 'Kernel core (/proc/kcore) format' \
+ "ELF CONFIG_KCORE_ELF \
+ A.OUT CONFIG_KCORE_AOUT" ELF
+fi
+tristate 'Kernel support for a.out binaries' CONFIG_BINFMT_AOUT
+tristate 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF
+tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC
+
+endmenu
+
+if [ "$CONFIG_NET" = "y" ]; then
+ source net/Config.in
+fi
+
+
+#
+# Block device driver configuration
+#
+mainmenu_option next_comment
+comment 'Block devices'
+tristate 'Loopback device support' CONFIG_BLK_DEV_LOOP
+dep_tristate 'Network block device support' CONFIG_BLK_DEV_NBD $CONFIG_NET
+tristate 'RAM disk support' CONFIG_BLK_DEV_RAM
+if [ "$CONFIG_BLK_DEV_RAM" = "y" -o "$CONFIG_BLK_DEV_RAM" = "m" ]; then
+ int ' Default RAM disk size' CONFIG_BLK_DEV_RAM_SIZE 4096
+fi
+dep_bool ' Initial RAM disk (initrd) support' CONFIG_BLK_DEV_INITRD $CONFIG_BLK_DEV_RAM
+bool 'Per partition statistics in /proc/partitions' CONFIG_BLK_STATS
+bool 'XenoLinux virtual block device support' CONFIG_XENOLINUX_BLOCK
+endmenu
+define_bool CONFIG_BLK_DEV_IDE_MODES n
+define_bool CONFIG_BLK_DEV_HD n
+
+
+mainmenu_option next_comment
+comment 'Character devices'
+
+bool 'Xen console support' CONFIG_XEN_CONSOLE
+comment 'The options below are alpha-stage and will probably not work'
+bool 'Virtual terminal' CONFIG_VT
+if [ "$CONFIG_VT" = "y" ]; then
+ bool ' Support for console on virtual terminal' CONFIG_VT_CONSOLE
+ bool ' Support for VGA Video' CONFIG_VGA_CONSOLE
+ bool ' Support for Dummy Video (for testing)' CONFIG_DUMMY_CONSOLE
+ bool ' PS/2 mouse (aka "auxiliary device") support' CONFIG_PSMOUSE
+fi
+
+bool 'Unix98 PTY support' CONFIG_UNIX98_PTYS
+if [ "$CONFIG_UNIX98_PTYS" = "y" ]; then
+ int 'Maximum number of Unix98 PTYs in use (0-2048)' CONFIG_UNIX98_PTY_COUNT 256
+fi
+
+endmenu
+
+source fs/Config.in
+
+mainmenu_option next_comment
+comment 'Kernel hacking'
+
+bool 'Kernel debugging' CONFIG_DEBUG_KERNEL
+if [ "$CONFIG_DEBUG_KERNEL" != "n" ]; then
+ bool ' Debug high memory support' CONFIG_DEBUG_HIGHMEM
+ bool ' Debug memory allocations' CONFIG_DEBUG_SLAB
+ bool ' Memory mapped I/O debugging' CONFIG_DEBUG_IOVIRT
+ bool ' Magic SysRq key' CONFIG_MAGIC_SYSRQ
+ bool ' Spinlock debugging' CONFIG_DEBUG_SPINLOCK
+ bool ' Verbose BUG() reporting (adds 70K)' CONFIG_DEBUG_BUGVERBOSE
+ bool ' Load all symbols for debugging' CONFIG_KALLSYMS
+ bool ' Compile the kernel with frame pointers' CONFIG_FRAME_POINTER
+fi
+
+endmenu
+
+source lib/Config.in
--- /dev/null
+#
+# Automatically generated make config: don't edit
+#
+CONFIG_XENO=y
+CONFIG_X86=y
+CONFIG_ISA=y
+# CONFIG_SBUS is not set
+CONFIG_UID16=y
+
+#
+# Code maturity level options
+#
+# CONFIG_EXPERIMENTAL is not set
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+CONFIG_MODVERSIONS=y
+CONFIG_KMOD=y
+
+#
+# Processor type and features
+#
+CONFIG_M686=y
+# CONFIG_MPENTIUMIII is not set
+# CONFIG_MPENTIUM4 is not set
+# CONFIG_MK7 is not set
+CONFIG_X86_WP_WORKS_OK=y
+CONFIG_X86_INVLPG=y
+CONFIG_X86_CMPXCHG=y
+CONFIG_X86_XADD=y
+CONFIG_X86_BSWAP=y
+CONFIG_X86_POPAD_OK=y
+# CONFIG_RWSEM_GENERIC_SPINLOCK is not set
+CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+CONFIG_X86_GOOD_APIC=y
+CONFIG_X86_PGE=y
+CONFIG_X86_USE_PPRO_CHECKSUM=y
+CONFIG_X86_TSC=y
+CONFIG_X86_L1_CACHE_SHIFT=5
+CONFIG_NOHIGHMEM=y
+# CONFIG_HIGHMEM4G is not set
+# CONFIG_HIGHMEM64G is not set
+
+#
+# General setup
+#
+CONFIG_NET=y
+CONFIG_SYSVIPC=y
+# CONFIG_BSD_PROCESS_ACCT is not set
+CONFIG_SYSCTL=y
+CONFIG_KCORE_ELF=y
+# CONFIG_KCORE_AOUT is not set
+CONFIG_BINFMT_AOUT=y
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_MISC is not set
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+CONFIG_PACKET_MMAP=y
+# CONFIG_NETLINK_DEV is not set
+# CONFIG_NETFILTER is not set
+CONFIG_FILTER=y
+CONFIG_UNIX=y
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_PNP=y
+# CONFIG_IP_PNP_DHCP is not set
+# CONFIG_IP_PNP_BOOTP is not set
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_INET_ECN is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_VLAN_8021Q is not set
+
+#
+#
+#
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+
+#
+# Appletalk devices
+#
+# CONFIG_DEV_APPLETALK is not set
+# CONFIG_DECNET is not set
+# CONFIG_BRIDGE is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+
+#
+# Block devices
+#
+# CONFIG_BLK_DEV_FD is not set
+# CONFIG_BLK_DEV_XD is not set
+# CONFIG_PARIDE is not set
+# CONFIG_BLK_CPQ_DA is not set
+# CONFIG_BLK_CPQ_CISS_DA is not set
+# CONFIG_CISS_SCSI_TAPE is not set
+# CONFIG_BLK_DEV_DAC960 is not set
+# CONFIG_BLK_DEV_UMEM is not set
+CONFIG_BLK_DEV_LOOP=y
+CONFIG_BLK_DEV_NBD=y
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_SIZE=4096
+CONFIG_BLK_DEV_INITRD=y
+# CONFIG_BLK_STATS is not set
+CONFIG_XENOLINUX_BLOCK=y
+# CONFIG_BLK_DEV_IDE_MODES is not set
+# CONFIG_BLK_DEV_HD is not set
+
+#
+# Character devices
+#
+CONFIG_XEN_CONSOLE=y
+# CONFIG_VT is not set
+# CONFIG_VGA_CONSOLE is not set
+# CONFIG_DUMMY_CONSOLE is not set
+# CONFIG_PSMOUSE is not set
+# CONFIG_UNIX98_PTYS is not set
+
+#
+# File systems
+#
+# CONFIG_QUOTA is not set
+CONFIG_AUTOFS_FS=y
+CONFIG_AUTOFS4_FS=y
+# CONFIG_REISERFS_FS is not set
+# CONFIG_REISERFS_CHECK is not set
+# CONFIG_REISERFS_PROC_INFO is not set
+# CONFIG_ADFS_FS is not set
+# CONFIG_ADFS_FS_RW is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BEFS_DEBUG is not set
+# CONFIG_BFS_FS is not set
+CONFIG_EXT3_FS=y
+CONFIG_JBD=y
+# CONFIG_JBD_DEBUG is not set
+# CONFIG_FAT_FS is not set
+# CONFIG_MSDOS_FS is not set
+# CONFIG_UMSDOS_FS is not set
+# CONFIG_VFAT_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_JFFS_FS is not set
+# CONFIG_JFFS2_FS is not set
+# CONFIG_CRAMFS is not set
+CONFIG_TMPFS=y
+CONFIG_RAMFS=y
+CONFIG_ISO9660_FS=y
+CONFIG_JOLIET=y
+CONFIG_ZISOFS=y
+# CONFIG_JFS_FS is not set
+# CONFIG_JFS_DEBUG is not set
+# CONFIG_JFS_STATISTICS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_NTFS_FS is not set
+# CONFIG_NTFS_RW is not set
+# CONFIG_HPFS_FS is not set
+CONFIG_PROC_FS=y
+# CONFIG_DEVFS_FS is not set
+# CONFIG_DEVFS_MOUNT is not set
+# CONFIG_DEVFS_DEBUG is not set
+# CONFIG_DEVPTS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_QNX4FS_RW is not set
+# CONFIG_ROMFS_FS is not set
+CONFIG_EXT2_FS=y
+# CONFIG_SYSV_FS is not set
+# CONFIG_UDF_FS is not set
+# CONFIG_UDF_RW is not set
+# CONFIG_UFS_FS is not set
+# CONFIG_UFS_FS_WRITE is not set
+
+#
+# Network File Systems
+#
+# CONFIG_CODA_FS is not set
+# CONFIG_INTERMEZZO_FS is not set
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+CONFIG_ROOT_NFS=y
+CONFIG_NFSD=y
+CONFIG_NFSD_V3=y
+# CONFIG_NFSD_TCP is not set
+CONFIG_SUNRPC=y
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+# CONFIG_SMB_FS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_NCPFS_PACKET_SIGNING is not set
+# CONFIG_NCPFS_IOCTL_LOCKING is not set
+# CONFIG_NCPFS_STRONG is not set
+# CONFIG_NCPFS_NFS_NS is not set
+# CONFIG_NCPFS_OS2_NS is not set
+# CONFIG_NCPFS_SMALLDOS is not set
+# CONFIG_NCPFS_NLS is not set
+# CONFIG_NCPFS_EXTRAS is not set
+CONFIG_ZISOFS_FS=y
+
+#
+# Partition Types
+#
+# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_SMB_NLS is not set
+CONFIG_NLS=y
+
+#
+# Native Language Support
+#
+CONFIG_NLS_DEFAULT="iso8559-1"
+# CONFIG_NLS_CODEPAGE_437 is not set
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+CONFIG_NLS_ISO8859_1=y
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+# CONFIG_NLS_UTF8 is not set
+
+#
+# Kernel hacking
+#
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_DEBUG_HIGHMEM is not set
+# CONFIG_DEBUG_SLAB is not set
+# CONFIG_DEBUG_IOVIRT is not set
+# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_BUGVERBOSE is not set
+CONFIG_KALLSYMS=y
+# CONFIG_FRAME_POINTER is not set
+
+#
+# Library routines
+#
+CONFIG_ZLIB_INFLATE=y
+# CONFIG_ZLIB_DEFLATE is not set
--- /dev/null
+O_TARGET := balloon_driver.o
+obj-y := balloon.o
+include $(TOPDIR)/Rules.make
--- /dev/null
+/******************************************************************************
+ * balloon.c
+ *
+ * Xeno balloon driver - enables returning/claiming memory to/from xen
+ *
+ * Copyright (c) 2003, B Dragovic
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/proc_fs.h>
+
+#include <linux/mm.h>
+#include <linux/mman.h>
+#include <linux/smp_lock.h>
+#include <linux/pagemap.h>
+
+#include <asm/hypervisor.h>
+#include <asm/pgalloc.h>
+#include <asm/pgtable.h>
+#include <asm/uaccess.h>
+#include <asm/tlb.h>
+
+#include "dom_mem_ops.h"
+
+/* USER DEFINES -- THESE SHOULD BE COPIED TO USER-SPACE TOOLS */
+#define USER_INFLATE_BALLOON 1 /* return mem to hypervisor */
+#define USER_DEFLATE_BALLOON 2 /* claim mem from hypervisor */
+typedef struct user_balloon_op {
+ unsigned int op;
+ unsigned long size;
+} user_balloon_op_t;
+/* END OF USER DEFINE */
+
+/* Dead entry written into ballon-owned entries in the PMT. */
+#define DEAD 0xdeadbeef
+
+#define BALLOON_ENTRY "balloon"
+extern struct proc_dir_entry *xeno_base;
+
+static struct proc_dir_entry *balloon_pde;
+unsigned long credit;
+
+static inline unsigned long get_ppte(unsigned long addr)
+{
+ unsigned long ppte;
+ pgd_t *pgd; pmd_t *pmd; pte_t *ptep;
+ pgd = pgd_offset_k(addr);
+
+ if ( pgd_none(*pgd) || pgd_bad(*pgd) ) BUG();
+
+ pmd = pmd_offset(pgd, addr);
+ if ( pmd_none(*pmd) || pmd_bad(*pmd) ) BUG();
+
+ ptep = pte_offset(pmd, addr);
+ ppte = (unsigned long)__pa(ptep);
+
+ return ppte;
+}
+
+/* main function for relinquishing bit of memory */
+static unsigned long inflate_balloon(unsigned long num_pages)
+{
+ dom_mem_op_t dom_mem_op;
+ unsigned long *parray;
+ unsigned long *currp;
+ unsigned long curraddr;
+ unsigned long ret = 0;
+ unsigned long vaddr;
+ unsigned long i, j;
+
+ parray = (unsigned long *)kmalloc(num_pages *
+ sizeof(unsigned long), GFP_KERNEL);
+ currp = parray;
+
+ for ( i = 0; i < num_pages; i++ )
+ {
+ /* try to obtain a free page, has to be done with GFP_ATOMIC
+ * as we do not want to sleep indefinately.
+ */
+ vaddr = __get_free_page(GFP_ATOMIC);
+
+ /* if allocation fails, free all reserved pages */
+ if(!vaddr){
+ printk("Unable to inflate balloon by %ld, only %ld pages free.",
+ num_pages, i);
+ currp = parray;
+ for(j = 0; j < i; j++){
+ free_page(*currp++);
+ }
+ goto cleanup;
+ }
+
+ *currp++ = vaddr;
+ }
+
+
+ currp = parray;
+ for ( i = 0; i < num_pages; i++ )
+ {
+ curraddr = *currp;
+ *currp = virt_to_machine(*currp) >> PAGE_SHIFT;
+ queue_l1_entry_update(get_ppte(curraddr) | PGREQ_NORMAL, 0);
+ phys_to_machine_mapping[__pa(curraddr) >> PAGE_SHIFT] = DEAD;
+ currp++;
+ }
+
+ XENO_flush_page_update_queue();
+
+ dom_mem_op.op = BALLOON_INFLATE_OP;
+ dom_mem_op.u.balloon_inflate.size = num_pages;
+ dom_mem_op.u.balloon_inflate.pages = parray;
+ if ( (ret = HYPERVISOR_dom_mem_op(&dom_mem_op)) != num_pages )
+ {
+ printk("Unable to inflate balloon, error %lx\n", ret);
+ goto cleanup;
+ }
+
+ credit += num_pages;
+ ret = num_pages;
+
+ cleanup:
+ kfree(parray);
+
+ return ret;
+}
+
+/* install new mem pages obtained by deflate_balloon. function walks
+ * phys->machine mapping table looking for DEAD entries and populates
+ * them.
+ */
+static unsigned long process_new_pages(unsigned long * parray,
+ unsigned long num)
+{
+ /* currently, this function is rather simplistic as
+ * it is assumed that domain reclaims only number of
+ * pages previously released. this is to change soon
+ * and the code to extend page tables etc. will be
+ * incorporated here.
+ */
+
+ unsigned long tot_pages = start_info.nr_pages;
+ unsigned long * curr = parray;
+ unsigned long num_installed;
+ unsigned long i;
+
+ num_installed = 0;
+ for ( i = 0; (i < tot_pages) && (num_installed < num); i++ )
+ {
+ if ( phys_to_machine_mapping[i] == DEAD )
+ {
+ printk(KERN_ALERT "bd240 debug: proc_new_pages: i %lx, mpt %lx, %lx\n", i, i << PAGE_SHIFT, get_ppte((unsigned long)__va(i << PAGE_SHIFT)) | PGREQ_NORMAL);
+ phys_to_machine_mapping[i] = *curr;
+ queue_l1_entry_update((i << PAGE_SHIFT) | PGREQ_MPT_UPDATE, i);
+ queue_l1_entry_update(
+ get_ppte((unsigned long)__va(i << PAGE_SHIFT)) | PGREQ_NORMAL,
+ ((*curr) << PAGE_SHIFT) | L1_PROT);
+
+ *curr = (unsigned long)__va(i << PAGE_SHIFT);
+ curr++;
+ num_installed++;
+ }
+ }
+
+ /* now, this is tricky (and will also change for machine addrs that
+ * are mapped to not previously released addresses). we free pages
+ * that were allocated by get_free_page (the mappings are different
+ * now, of course).
+ */
+ curr = parray;
+ for ( i = 0; i < num_installed; i++ )
+ {
+ free_page(*curr);
+ curr++;
+ }
+
+ return num_installed;
+}
+
+unsigned long deflate_balloon(unsigned long num_pages)
+{
+ dom_mem_op_t dom_mem_op;
+ unsigned long ret;
+ unsigned long * parray;
+
+ printk(KERN_ALERT "bd240 debug: deflate balloon called for %lx pages\n", num_pages);
+
+ if ( num_pages > credit )
+ {
+ printk("Can not allocate more pages than previously released.\n");
+ return -EAGAIN;
+ }
+
+ parray = (unsigned long *)kmalloc(num_pages * sizeof(unsigned long),
+ GFP_KERNEL);
+
+ dom_mem_op.op = BALLOON_DEFLATE_OP;
+ dom_mem_op.u.balloon_deflate.size = num_pages;
+ dom_mem_op.u.balloon_deflate.pages = parray;
+ if((ret = HYPERVISOR_dom_mem_op(&dom_mem_op)) != num_pages){
+ printk("Unable to deflate balloon, error %lx\n", ret);
+ goto cleanup;
+ }
+
+ if((ret = process_new_pages(parray, num_pages)) < num_pages){
+ printk("Unable to deflate balloon by specified %lx pages, only %lx.\n",
+ num_pages, ret);
+ goto cleanup;
+ }
+
+ ret = num_pages;
+ credit -= num_pages;
+
+ cleanup:
+ kfree(parray);
+
+ return ret;
+}
+
+static int balloon_write(struct file *file, const char *buffer,
+ u_long count, void *data)
+{
+ user_balloon_op_t bop;
+
+ /* Only admin can play with the balloon :) */
+ if ( !capable(CAP_SYS_ADMIN) )
+ return -EPERM;
+
+ if ( copy_from_user(&bop, buffer, sizeof(bop)) )
+ return -EFAULT;
+
+ switch ( bop.op )
+ {
+ case USER_INFLATE_BALLOON:
+ if ( inflate_balloon(bop.size) < bop.size )
+ return -EAGAIN;
+ break;
+
+ case USER_DEFLATE_BALLOON:
+ deflate_balloon(bop.size);
+ break;
+
+ default:
+ printk("Unknown command to balloon driver.");
+ return -EFAULT;
+ }
+
+ return sizeof(bop);
+}
+
+/*
+ * main balloon driver initialization function.
+ */
+static int __init init_module(void)
+{
+ printk(KERN_ALERT "Starting Xeno Balloon driver\n");
+
+ credit = 0;
+
+ balloon_pde = create_proc_entry(BALLOON_ENTRY, 0600, xeno_base);
+ if ( balloon_pde == NULL )
+ {
+ printk(KERN_ALERT "Unable to create balloon driver proc entry!");
+ return -1;
+ }
+
+ balloon_pde->write_proc = balloon_write;
+
+ return 0;
+}
+
+static void __exit cleanup_module(void)
+{
+}
+
+module_init(init_module);
+module_exit(cleanup_module);
+
+
--- /dev/null
+/******************************************************************************
+ * dom_mem_ops.h
+ *
+ * Header file supporting domain related memory operations. N.B. keep in sync
+ * with xen version.
+ *
+ * Copyright (c) 2003, B Dragovic
+ */
+
+#define L1_PROT (_PAGE_PRESENT|_PAGE_RW|_PAGE_USER|_PAGE_ACCESSED)
+#define BALLOON_DEFLATE_OP 0
+#define BALLOON_INFLATE_OP 1
+
+typedef struct balloon_deflate_op {
+ unsigned long size;
+ unsigned long * pages;
+} balloon_def_op_t;
+
+typedef struct balloon_inflate_op {
+ unsigned long size;
+ unsigned long * pages;
+} balloon_inf_op_t;
+
+typedef struct dom_mem_ops
+{
+ unsigned int op;
+ union
+ {
+ balloon_def_op_t balloon_deflate;
+ balloon_inf_op_t balloon_inflate;
+ }u;
+} dom_mem_op_t;
--- /dev/null
+O_TARGET := blk.o
+obj-y := xl_block.o xl_ide.o xl_scsi.o xl_segment.o xl_segment_proc.o
+include $(TOPDIR)/Rules.make
--- /dev/null
+/******************************************************************************
+ * xl_block.c
+ *
+ * Xenolinux virtual block-device driver.
+ *
+ */
+
+#include "xl_block.h"
+#include <linux/blk.h>
+#include <linux/cdrom.h>
+
+typedef unsigned char byte; /* from linux/ide.h */
+
+#define XLBLK_RESPONSE_IRQ _EVENT_BLK_RESP
+#define DEBUG_IRQ _EVENT_DEBUG
+
+static blk_ring_t *blk_ring;
+static unsigned int resp_cons; /* Response consumer for comms ring. */
+static unsigned int req_prod; /* Private request producer. */
+static xen_disk_info_t xlblk_disk_info;
+static int xlblk_control_msg_pending;
+
+#define RING_FULL (BLK_RING_INC(req_prod) == resp_cons)
+
+/*
+ * Request queues with outstanding work, but ring is currently full.
+ * We need no special lock here, as we always access this with the
+ * io_request_lock held. We only need a small maximum list.
+ */
+#define MAX_PENDING 8
+static request_queue_t *pending_queues[MAX_PENDING];
+static int nr_pending;
+
+static kdev_t sg_dev;
+static int sg_operation = -1;
+static unsigned long sg_next_sect;
+#define DISABLE_SCATTERGATHER() (sg_operation = -1)
+
+static inline void signal_requests_to_xen(void)
+{
+ DISABLE_SCATTERGATHER();
+ blk_ring->req_prod = req_prod;
+ HYPERVISOR_block_io_op();
+}
+
+/* Convert from a XenoLinux major device to the Xen-level 'physical' device */
+inline unsigned short xldev_to_physdev(kdev_t xldev)
+{
+ unsigned short physdev = 0;
+
+ switch ( MAJOR(xldev) )
+ {
+ case XLIDE_MAJOR_0:
+ physdev = XENDEV_IDE + (0*XLIDE_DEVS_PER_MAJOR) +
+ (MINOR(xldev) >> XLIDE_PARTN_SHIFT);
+ break;
+
+ case XLIDE_MAJOR_1:
+ physdev = XENDEV_IDE + (1*XLIDE_DEVS_PER_MAJOR) +
+ (MINOR(xldev) >> XLIDE_PARTN_SHIFT);
+ break;
+
+ case XLSCSI_MAJOR:
+ physdev = XENDEV_SCSI + (MINOR(xldev) >> XLSCSI_PARTN_SHIFT);
+ break;
+
+ case XLVIRT_MAJOR:
+ physdev = XENDEV_VIRTUAL + (MINOR(xldev) >> XLVIRT_PARTN_SHIFT);
+ break;
+ }
+
+ if ( physdev == 0 ) BUG();
+
+ return physdev;
+}
+
+
+static inline struct gendisk *xldev_to_gendisk(kdev_t xldev)
+{
+ struct gendisk *gd = NULL;
+
+ switch ( MAJOR(xldev) )
+ {
+ case XLIDE_MAJOR_0:
+ gd = xlide_gendisk[0];
+ break;
+
+ case XLIDE_MAJOR_1:
+ gd = xlide_gendisk[1];
+ break;
+
+ case XLSCSI_MAJOR:
+ gd = xlscsi_gendisk;
+ break;
+
+ case XLVIRT_MAJOR:
+ gd = xlsegment_gendisk;
+ break;
+ }
+
+ if ( gd == NULL ) BUG();
+
+ return gd;
+}
+
+
+static inline xl_disk_t *xldev_to_xldisk(kdev_t xldev)
+{
+ struct gendisk *gd = xldev_to_gendisk(xldev);
+ return (xl_disk_t *)gd->real_devices +
+ (MINOR(xldev) >> PARTN_SHIFT(xldev));
+}
+
+
+int xenolinux_block_open(struct inode *inode, struct file *filep)
+{
+ xl_disk_t *disk = xldev_to_xldisk(inode->i_rdev);
+ disk->usage++;
+ DPRINTK("xenolinux_block_open\n");
+ return 0;
+}
+
+
+int xenolinux_block_release(struct inode *inode, struct file *filep)
+{
+ xl_disk_t *disk = xldev_to_xldisk(inode->i_rdev);
+ disk->usage--;
+ DPRINTK("xenolinux_block_release\n");
+ return 0;
+}
+
+/*
+ * handle ioctl calls
+ *
+ * individual ioctls are defined in /usr/include/linux/fs.h
+ */
+
+int xenolinux_block_ioctl(struct inode *inode, struct file *filep,
+ unsigned command, unsigned long argument)
+{
+ kdev_t dev = inode->i_rdev;
+ struct hd_geometry *geo = (struct hd_geometry *)argument;
+ struct gendisk *gd;
+ struct hd_struct *part;
+
+ DPRINTK("xenolinux_block_ioctl\n");
+
+ /* check permissions */
+ if (!capable(CAP_SYS_ADMIN)) return -EPERM;
+ if (!inode) return -EINVAL;
+
+ DPRINTK_IOCTL("command: 0x%x, argument: 0x%lx, dev: 0x%04x\n",
+ command, (long) argument, dev);
+
+ gd = xldev_to_gendisk(dev);
+ part = &gd->part[MINOR(dev)];
+
+ switch ( command )
+ {
+ case BLKGETSIZE:
+ DPRINTK_IOCTL(" BLKGETSIZE: %x %lx\n", BLKGETSIZE, part->nr_sects);
+ return put_user(part->nr_sects, (unsigned long *) argument);
+
+ case BLKRRPART: /* re-read partition table */
+ DPRINTK_IOCTL(" BLKRRPART: %x\n", BLKRRPART);
+ return xenolinux_block_revalidate(dev);
+
+ case BLKSSZGET:
+ switch ( MAJOR(dev) )
+ {
+ case XLIDE_MAJOR_0:
+ DPRINTK_IOCTL(" BLKSSZGET: %x 0x%x\n", BLKSSZGET,
+ xlide_hwsect(MINOR(dev)));
+ return xlide_hwsect(MINOR(dev));
+
+ case XLSCSI_MAJOR:
+ DPRINTK_IOCTL(" BLKSSZGET: %x 0x%x\n", BLKSSZGET,
+ xlscsi_hwsect(MINOR(dev)));
+ return xlscsi_hwsect(MINOR(dev));
+
+ case XLVIRT_MAJOR:
+ DPRINTK_IOCTL(" BLKSSZGET: %x 0x%x\n", BLKSSZGET,
+ xlsegment_hwsect(MINOR(dev)));
+ return xlsegment_hwsect(MINOR(dev));
+
+ default:
+ printk(KERN_ALERT "BLKSSZGET ioctl() on bogus disk!\n");
+ return 0;
+ }
+
+ case BLKBSZGET: /* get block size */
+ DPRINTK_IOCTL(" BLKBSZGET: %x\n", BLKBSZGET);
+ break;
+
+ case BLKBSZSET: /* set block size */
+ DPRINTK_IOCTL(" BLKBSZSET: %x\n", BLKBSZSET);
+ break;
+
+ case BLKRASET: /* set read-ahead */
+ DPRINTK_IOCTL(" BLKRASET: %x\n", BLKRASET);
+ break;
+
+ case BLKRAGET: /* get read-ahead */
+ DPRINTK_IOCTL(" BLKRAFET: %x\n", BLKRAGET);
+ break;
+
+ case HDIO_GETGEO:
+ /* note: these values are complete garbage */
+ DPRINTK_IOCTL(" HDIO_GETGEO: %x\n", HDIO_GETGEO);
+ if (!argument) return -EINVAL;
+ if (put_user(0x00, (unsigned long *) &geo->start)) return -EFAULT;
+ if (put_user(0xff, (byte *)&geo->heads)) return -EFAULT;
+ if (put_user(0x3f, (byte *)&geo->sectors)) return -EFAULT;
+ if (put_user(0x106, (unsigned short *)&geo->cylinders)) return -EFAULT;
+ return 0;
+
+ case HDIO_GETGEO_BIG:
+ /* note: these values are complete garbage */
+ DPRINTK_IOCTL(" HDIO_GETGEO_BIG: %x\n", HDIO_GETGEO_BIG);
+ if (!argument) return -EINVAL;
+ if (put_user(0x00, (unsigned long *) &geo->start)) return -EFAULT;
+ if (put_user(0xff, (byte *)&geo->heads)) return -EFAULT;
+ if (put_user(0x3f, (byte *)&geo->sectors)) return -EFAULT;
+ if (put_user(0x106, (unsigned int *) &geo->cylinders)) return -EFAULT;
+ return 0;
+
+ case CDROMMULTISESSION:
+ printk("FIXME: support multisession CDs later\n");
+ memset((struct cdrom_multisession *)argument, 0,
+ sizeof(struct cdrom_multisession));
+ return 0;
+
+ default:
+ printk("ioctl %08x not supported by xl_block\n", command);
+ return -ENOSYS;
+ }
+
+ return 0;
+}
+
+int xenolinux_block_check(kdev_t dev)
+{
+ DPRINTK("xenolinux_block_check\n");
+ return 0;
+}
+
+int xenolinux_block_revalidate(kdev_t dev)
+{
+ struct gendisk *gd = xldev_to_gendisk(dev);
+ xl_disk_t *disk = xldev_to_xldisk(dev);
+ unsigned long flags;
+ int i, partn_shift = PARTN_SHIFT(dev);
+ int xdev = dev & XENDEV_IDX_MASK;
+
+ DPRINTK("xenolinux_block_revalidate: %d %d %d\n",
+ dev, xdev, XENDEV_IDX_MASK);
+
+ spin_lock_irqsave(&io_request_lock, flags);
+ if ( disk->usage > 1 )
+ {
+ spin_unlock_irqrestore(&io_request_lock, flags);
+ return -EBUSY;
+ }
+ spin_unlock_irqrestore(&io_request_lock, flags);
+
+ for ( i = 0; i < (1 << partn_shift); i++ )
+ {
+ invalidate_device(xdev + i, 1);
+ gd->part[xdev + i].start_sect = 0;
+ gd->part[xdev + i].nr_sects = 0;
+ }
+
+ grok_partitions(gd, MINOR(dev) >> partn_shift,
+ 1 << partn_shift, disk->capacity);
+
+ return 0;
+}
+
+
+/*
+ * hypervisor_request
+ *
+ * request block io
+ *
+ * id: for guest use only.
+ * operation: XEN_BLOCK_{READ,WRITE,PROBE*,SEG*}
+ * buffer: buffer to read/write into. this should be a
+ * virtual address in the guest os.
+ */
+static int hypervisor_request(unsigned long id,
+ int operation,
+ char * buffer,
+ unsigned long sector_number,
+ unsigned short nr_sectors,
+ kdev_t device)
+{
+ unsigned long buffer_ma = phys_to_machine(virt_to_phys(buffer));
+ kdev_t phys_device = (kdev_t) 0;
+ struct gendisk *gd;
+ blk_ring_req_entry_t *req;
+ struct buffer_head *bh;
+
+ if ( nr_sectors >= (1<<9) ) BUG();
+ if ( (buffer_ma & ((1<<9)-1)) != 0 ) BUG();
+
+ switch ( operation )
+ {
+ case XEN_BLOCK_SEG_CREATE:
+ case XEN_BLOCK_SEG_DELETE:
+ case XEN_BLOCK_PROBE_BLK:
+ case XEN_BLOCK_PROBE_SEG:
+ if ( RING_FULL ) return 1;
+ phys_device = (kdev_t) 0;
+ sector_number = 0;
+ DISABLE_SCATTERGATHER();
+ break;
+
+ case XEN_BLOCK_READ:
+ case XEN_BLOCK_WRITE:
+ phys_device = xldev_to_physdev(device);
+ gd = xldev_to_gendisk(device);
+
+ sector_number += gd->part[MINOR(device)].start_sect;
+ if ( (sg_operation == operation) &&
+ (sg_dev == phys_device) &&
+ (sg_next_sect == sector_number) )
+ {
+ req = &blk_ring->ring[(req_prod-1)&(BLK_RING_SIZE-1)].req;
+ bh = (struct buffer_head *)id;
+ bh->b_reqnext = (struct buffer_head *)req->id;
+ req->id = id;
+ req->buffer_and_sects[req->nr_segments] = buffer_ma | nr_sectors;
+ if ( ++req->nr_segments < MAX_BLK_SEGS )
+ sg_next_sect += nr_sectors;
+ else
+ DISABLE_SCATTERGATHER();
+ return 0;
+ }
+ else if ( RING_FULL )
+ {
+ return 1;
+ }
+ else
+ {
+ sg_operation = operation;
+ sg_dev = phys_device;
+ sg_next_sect = sector_number + nr_sectors;
+ }
+ break;
+
+ default:
+ panic("unknown op %d\n", operation);
+ }
+
+ /* Fill out a communications ring structure. */
+ req = &blk_ring->ring[req_prod].req;
+ req->id = id;
+ req->operation = operation;
+ req->sector_number = sector_number;
+ req->device = phys_device;
+ req->nr_segments = 1;
+ req->buffer_and_sects[0] = buffer_ma | nr_sectors;
+ req_prod = BLK_RING_INC(req_prod);
+
+ return 0;
+}
+
+
+/*
+ * do_xlblk_request
+ * read a block; request is in a request queue
+ */
+void do_xlblk_request(request_queue_t *rq)
+{
+ struct request *req;
+ struct buffer_head *bh, *next_bh;
+ int rw, nsect, full, queued = 0;
+
+ DPRINTK("xlblk.c::do_xlblk_request for '%s'\n", DEVICE_NAME);
+
+ while ( !rq->plugged && !list_empty(&rq->queue_head))
+ {
+ if ( (req = blkdev_entry_next_request(&rq->queue_head)) == NULL )
+ goto out;
+
+ DPRINTK("do_xlblk_request %p: cmd %i, sec %lx, (%li/%li) bh:%p\n",
+ req, req->cmd, req->sector,
+ req->current_nr_sectors, req->nr_sectors, req->bh);
+
+ rw = req->cmd;
+ if ( rw == READA ) rw = READ;
+ if ((rw != READ) && (rw != WRITE))
+ panic("XenoLinux Virtual Block Device: bad cmd: %d\n", rw);
+
+ req->errors = 0;
+
+ bh = req->bh;
+ while ( bh != NULL )
+ {
+ next_bh = bh->b_reqnext;
+ bh->b_reqnext = NULL;
+
+ full = hypervisor_request(
+ (unsigned long)bh,
+ (rw == READ) ? XEN_BLOCK_READ : XEN_BLOCK_WRITE,
+ bh->b_data, bh->b_rsector, bh->b_size>>9, bh->b_rdev);
+
+ if ( full )
+ {
+ bh->b_reqnext = next_bh;
+ pending_queues[nr_pending++] = rq;
+ if ( nr_pending >= MAX_PENDING ) BUG();
+ goto out;
+ }
+
+ queued++;
+
+ /* Dequeue the buffer head from the request. */
+ nsect = bh->b_size >> 9;
+ bh = req->bh = next_bh;
+
+ if ( bh != NULL )
+ {
+ /* There's another buffer head to do. Update the request. */
+ req->hard_sector += nsect;
+ req->hard_nr_sectors -= nsect;
+ req->sector = req->hard_sector;
+ req->nr_sectors = req->hard_nr_sectors;
+ req->current_nr_sectors = bh->b_size >> 9;
+ req->buffer = bh->b_data;
+ }
+ else
+ {
+ /* That was the last buffer head. Finalise the request. */
+ if ( end_that_request_first(req, 1, "XenBlk") ) BUG();
+ blkdev_dequeue_request(req);
+ end_that_request_last(req);
+ }
+ }
+ }
+
+ out:
+ if ( queued != 0 ) signal_requests_to_xen();
+}
+
+
+static void xlblk_response_int(int irq, void *dev_id, struct pt_regs *ptregs)
+{
+ int i;
+ unsigned long flags;
+ struct buffer_head *bh, *next_bh;
+
+ spin_lock_irqsave(&io_request_lock, flags);
+
+ for ( i = resp_cons;
+ i != blk_ring->resp_prod;
+ i = BLK_RING_INC(i) )
+ {
+ blk_ring_resp_entry_t *bret = &blk_ring->ring[i].resp;
+ switch (bret->operation)
+ {
+ case XEN_BLOCK_READ:
+ case XEN_BLOCK_WRITE:
+ if ( bret->status )
+ printk(KERN_ALERT "Bad return from blkdev data request: %lx\n",
+ bret->status);
+ for ( bh = (struct buffer_head *)bret->id;
+ bh != NULL;
+ bh = next_bh )
+ {
+ next_bh = bh->b_reqnext;
+ bh->b_reqnext = NULL;
+ bh->b_end_io(bh, !bret->status);
+ }
+ break;
+
+ case XEN_BLOCK_SEG_CREATE:
+ case XEN_BLOCK_SEG_DELETE:
+ case XEN_BLOCK_PROBE_SEG:
+ case XEN_BLOCK_PROBE_BLK:
+ if ( bret->status )
+ printk(KERN_ALERT "Bad return from blkdev control request\n");
+ xlblk_control_msg_pending = 0;
+ break;
+
+ default:
+ BUG();
+ }
+ }
+
+ resp_cons = i;
+
+ /* We kick pending request queues if the ring is reasonably empty. */
+ if ( (nr_pending != 0) &&
+ (((req_prod - resp_cons) & (BLK_RING_SIZE - 1)) <
+ (BLK_RING_SIZE >> 1)) )
+ {
+ /* Attempt to drain the queue, but bail if the ring becomes full. */
+ while ( nr_pending != 0 )
+ {
+ do_xlblk_request(pending_queues[--nr_pending]);
+ if ( RING_FULL ) break;
+ }
+ }
+
+ spin_unlock_irqrestore(&io_request_lock, flags);
+}
+
+
+/* Send a synchronous message to Xen. */
+int xenolinux_control_msg(int operation, char *buffer, int size)
+{
+ unsigned long flags;
+ char *aligned_buf;
+
+ /* We copy from an aligned buffer, as interface needs sector alignment. */
+ aligned_buf = (char *)get_free_page(GFP_KERNEL);
+ if ( aligned_buf == NULL ) BUG();
+ memcpy(aligned_buf, buffer, size);
+
+ xlblk_control_msg_pending = 1;
+ spin_lock_irqsave(&io_request_lock, flags);
+ /* Note that size gets rounded up to a sector-sized boundary. */
+ if ( hypervisor_request(0, operation, aligned_buf, 0, (size+511)/512, 0) )
+ return -EAGAIN;
+ signal_requests_to_xen();
+ spin_unlock_irqrestore(&io_request_lock, flags);
+ while ( xlblk_control_msg_pending ) barrier();
+
+ memcpy(buffer, aligned_buf, size);
+ free_page((unsigned long)aligned_buf);
+
+ return 0;
+}
+
+
+int __init xlblk_init(void)
+{
+ int error;
+
+ xlblk_control_msg_pending = 0;
+ nr_pending = 0;
+
+ /* This mapping was created early at boot time. */
+ blk_ring = (blk_ring_t *)fix_to_virt(FIX_BLKRING_BASE);
+ blk_ring->req_prod = blk_ring->resp_prod = resp_cons = req_prod = 0;
+
+ error = request_irq(XLBLK_RESPONSE_IRQ, xlblk_response_int,
+ SA_SAMPLE_RANDOM, "xlblk-response", NULL);
+ if ( error )
+ {
+ printk(KERN_ALERT "Could not allocate receive interrupt\n");
+ goto fail;
+ }
+
+ /* Probe for disk information. */
+ memset(&xlblk_disk_info, 0, sizeof(xlblk_disk_info));
+ error = xenolinux_control_msg(XEN_BLOCK_PROBE_BLK,
+ (char *)&xlblk_disk_info,
+ sizeof(xen_disk_info_t));
+ if ( error )
+ {
+ printk(KERN_ALERT "Could not probe disks (%d)\n", error);
+ free_irq(XLBLK_RESPONSE_IRQ, NULL);
+ goto fail;
+ }
+
+ /* Pass the information to our fake IDE and SCSI susbystems. */
+ xlide_init(&xlblk_disk_info);
+ xlscsi_init(&xlblk_disk_info);
+
+ return 0;
+
+ fail:
+ return error;
+}
+
+static void __exit xlblk_cleanup(void)
+{
+ xlide_cleanup();
+ xlscsi_cleanup();
+ free_irq(XLBLK_RESPONSE_IRQ, NULL);
+}
+
+
+#ifdef MODULE
+module_init(xlblk_init);
+module_exit(xlblk_cleanup);
+#endif
--- /dev/null
+/******************************************************************************
+ * xl_block.h
+ *
+ * Shared definitions between all levels of XenoLinux Virtual block devices.
+ */
+
+#ifndef __XL_BLOCK_H__
+#define __XL_BLOCK_H__
+
+#include <linux/config.h>
+#include <linux/module.h>
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+
+#include <linux/fs.h>
+#include <linux/hdreg.h>
+#include <linux/blkdev.h>
+#include <linux/major.h>
+
+#include <asm/hypervisor-ifs/block.h>
+#include <asm/hypervisor-ifs/hypervisor-if.h>
+#include <asm/io.h>
+#include <asm/atomic.h>
+#include <asm/uaccess.h>
+
+#if 0
+#define DPRINTK(_f, _a...) printk ( KERN_ALERT _f , ## _a )
+#else
+#define DPRINTK(_f, _a...) ((void)0)
+#endif
+
+#if 0
+#define DPRINTK_IOCTL(_f, _a...) printk ( KERN_ALERT _f , ## _a )
+#else
+#define DPRINTK_IOCTL(_f, _a...) ((void)0)
+#endif
+
+/* XL IDE and SCSI use same major/minor numbers as normal Linux devices. */
+#define XLIDE_MAJOR_0 IDE0_MAJOR
+#define XLIDE_MAJOR_1 IDE1_MAJOR
+#define XLSCSI_MAJOR SCSI_DISK0_MAJOR
+
+#define XLIDE_PARTN_SHIFT 6
+#define XLSCSI_PARTN_SHIFT 4
+#define XLVIRT_PARTN_SHIFT 4
+
+static inline int PARTN_SHIFT(kdev_t dev)
+{
+ switch ( MAJOR(dev) )
+ {
+ case XLIDE_MAJOR_0:
+ case XLIDE_MAJOR_1:
+ return XLIDE_PARTN_SHIFT;
+ case XLSCSI_MAJOR:
+ return XLSCSI_PARTN_SHIFT;
+ case XLVIRT_MAJOR:
+ return XLVIRT_PARTN_SHIFT;
+ default:
+ BUG();
+ }
+}
+
+#define XLIDE_DEVS_PER_MAJOR 2
+#define XLSCSI_DEVS_PER_MAJOR 16
+#define XLVIRT_DEVS_PER_MAJOR 16
+
+/*
+ * We have one of these per XL-IDE, XL-SCSI, and XL-VIRT device.
+ * They hang in an array off the gendisk structure. We may end up putting
+ * all kinds of interesting stuff here :-)
+ */
+typedef struct xl_disk {
+ int usage;
+ unsigned long capacity;
+} xl_disk_t;
+
+/* Generic layer. */
+extern int xenolinux_control_msg(int operration, char *buffer, int size);
+extern int xenolinux_block_open(struct inode *inode, struct file *filep);
+extern int xenolinux_block_release(struct inode *inode, struct file *filep);
+extern int xenolinux_block_ioctl(struct inode *inode, struct file *filep,
+ unsigned command, unsigned long argument);
+extern int xenolinux_block_check(kdev_t dev);
+extern int xenolinux_block_revalidate(kdev_t dev);
+extern void do_xlblk_request (request_queue_t *rq);
+
+/* Fake IDE subsystem. */
+extern int xlide_init(xen_disk_info_t *xdi);
+extern int xlide_hwsect(int minor);
+extern void xlide_cleanup(void);
+extern struct gendisk *xlide_gendisk[];
+
+/* Fake SCSI subsystem. */
+extern int xlscsi_init(xen_disk_info_t *xdi);
+extern int xlscsi_hwsect(int minor);
+extern void xlscsi_cleanup(void);
+extern struct gendisk *xlscsi_gendisk;
+
+/* Virtual block-device subsystem. */
+extern int xlsegment_hwsect(int minor);
+extern struct gendisk *xlsegment_gendisk;
+
+#endif /* __XL_BLOCK_H__ */
--- /dev/null
+/******************************************************************************
+ * xl_ide.c
+ *
+ * Xenolinux virtual IDE block-device driver.
+ */
+
+#include "xl_block.h"
+#include <linux/blk.h>
+
+#define XLIDE_MAX 256
+#define XLIDE_MAJOR_NAME "hd"
+static int xlide_blksize_size[XLIDE_MAX];
+static int xlide_hardsect_size[XLIDE_MAX];
+static int xlide_max_sectors[XLIDE_MAX];
+
+#define XLIDE_NR_MAJORS 2
+
+struct gendisk *xlide_gendisk[XLIDE_NR_MAJORS] = { NULL };
+
+static struct block_device_operations xlide_block_fops =
+{
+ open: xenolinux_block_open,
+ release: xenolinux_block_release,
+ ioctl: xenolinux_block_ioctl,
+ check_media_change: xenolinux_block_check,
+ revalidate: xenolinux_block_revalidate,
+};
+
+int xlide_hwsect(int minor)
+{
+ return xlide_hardsect_size[minor];
+}
+
+static int get_major(int major)
+{
+ int r = register_blkdev(major, XLIDE_MAJOR_NAME, &xlide_block_fops);
+ if ( r < 0 )
+ printk (KERN_ALERT "XL IDE: can't get major %d\n", XLIDE_MAJOR_0);
+ return r;
+}
+
+static void setup_major(struct gendisk **pgd,
+ xen_disk_info_t *xdi, int base, int major)
+{
+ int i, minors, disk, units = XLIDE_DEVS_PER_MAJOR;
+ unsigned short minor;
+ unsigned char buf[64];
+ struct gendisk *gd;
+
+ blk_size[major] = NULL;
+ blksize_size[major] = xlide_blksize_size + base*(1<<XLIDE_PARTN_SHIFT);
+ hardsect_size[major] = xlide_hardsect_size + base*(1<<XLIDE_PARTN_SHIFT);
+ max_sectors[major] = xlide_max_sectors + base*(1<<XLIDE_PARTN_SHIFT);
+ read_ahead[major] = 8;
+
+ blk_init_queue(BLK_DEFAULT_QUEUE(major), do_xlblk_request);
+
+ /*
+ * Turn off barking 'headactive' mode. We dequeue buffer heads as soon as
+ * we pass them down to Xen.
+ */
+ blk_queue_headactive(BLK_DEFAULT_QUEUE(major), 0);
+
+ /* Construct an appropriate gendisk structure. */
+ minors = units * (1<<XLIDE_PARTN_SHIFT);
+ gd = kmalloc(sizeof(struct gendisk), GFP_KERNEL);
+ gd->sizes = kmalloc(minors * sizeof(int), GFP_KERNEL);
+ gd->part = kmalloc(minors * sizeof(struct hd_struct), GFP_KERNEL);
+ gd->major = major;
+ gd->major_name = XLIDE_MAJOR_NAME;
+ gd->minor_shift = XLIDE_PARTN_SHIFT;
+ gd->max_p = 1<<XLIDE_PARTN_SHIFT;
+ gd->nr_real = units;
+ gd->real_devices = kmalloc(units * sizeof(xl_disk_t), GFP_KERNEL);
+ gd->next = NULL;
+ gd->fops = &xlide_block_fops;
+ gd->de_arr = kmalloc(sizeof(*gd->de_arr) * units, GFP_KERNEL);
+ gd->flags = kmalloc(sizeof(*gd->flags) * units, GFP_KERNEL);
+ memset(gd->sizes, 0, minors * sizeof(int));
+ memset(gd->part, 0, minors * sizeof(struct hd_struct));
+ memset(gd->de_arr, 0, sizeof(*gd->de_arr) * units);
+ memset(gd->flags, 0, sizeof(*gd->flags) * units);
+ memset(gd->real_devices, 0, sizeof(xl_disk_t) * units);
+ *pgd = gd;
+ add_gendisk(gd);
+
+ /* Now register each disk in turn. */
+ for ( i = 0; i < xdi->count; i++ )
+ {
+ disk = xdi->disks[i].device & XENDEV_IDX_MASK;
+ minor = (disk-base) << XLIDE_PARTN_SHIFT;
+
+ if ( !IS_IDE_XENDEV(xdi->disks[i].device) ||
+ (disk < base) || (disk >= (base + XLIDE_DEVS_PER_MAJOR)) )
+ continue;
+
+ ((xl_disk_t *)gd->real_devices)[disk].capacity =
+ xdi->disks[i].capacity;
+
+ switch (xdi->disks[i].type)
+ {
+ case XD_TYPE_CDROM:
+ set_device_ro(MKDEV(major, minor), 1);
+
+ case XD_TYPE_FLOPPY:
+ case XD_TYPE_TAPE:
+ gd->flags[disk] = GENHD_FL_REMOVABLE;
+ printk(KERN_ALERT "Skipping partition check on %s /dev/%s\n",
+ xdi->disks[i].type==XD_TYPE_CDROM ? "cdrom" :
+ (xdi->disks[i].type==XD_TYPE_TAPE ? "tape" : "floppy"),
+ disk_name(gd, minor, buf));
+ break;
+
+ case XD_TYPE_DISK:
+ register_disk(gd,
+ MKDEV(major, minor),
+ 1<<XLIDE_PARTN_SHIFT,
+ &xlide_block_fops, xdi->disks[i].capacity);
+ break;
+
+ default:
+ printk(KERN_ALERT "XenoLinux: unknown ide device type %d\n",
+ xdi->disks[i].type);
+ break;
+ }
+ }
+
+ return gd;
+}
+
+
+int xlide_init(xen_disk_info_t *xdi)
+{
+ int i, units;
+
+ /* If we don't have any usable IDE devices we may as well bail now. */
+ units = 0;
+ for ( i = 0; i < xdi->count; i++ )
+ if ( IS_IDE_XENDEV(xdi->disks[i].device) &&
+ ((xdi->disks[i].device & XENDEV_IDX_MASK) <
+ (XLIDE_NR_MAJORS*XLIDE_DEVS_PER_MAJOR)) )
+ units++;
+ if ( units == 0 ) return 0;
+
+ SET_MODULE_OWNER(&xlide_block_fops);
+
+ if ( get_major(XLIDE_MAJOR_0) < 0 )
+ return 0;
+ if ( get_major(XLIDE_MAJOR_1) < 0 )
+ {
+ (void)unregister_blkdev(XLIDE_MAJOR_0, XLIDE_MAJOR_NAME);
+ return 0;
+ }
+
+ /* Initialize global arrays. */
+ for ( i = 0; i < XLIDE_MAX; i++ )
+ {
+ xlide_blksize_size[i] = 512;
+ xlide_hardsect_size[i] = 512;
+ xlide_max_sectors[i] = 128;
+ }
+
+ setup_major(&xlide_gendisk[0], xdi, 0*XLIDE_DEVS_PER_MAJOR, XLIDE_MAJOR_0);
+ setup_major(&xlide_gendisk[1], xdi, 1*XLIDE_DEVS_PER_MAJOR, XLIDE_MAJOR_1);
+
+ return 0;
+}
+
+
+static void cleanup_major(int major)
+{
+ blk_cleanup_queue(BLK_DEFAULT_QUEUE(major));
+
+ read_ahead[major] = 0;
+
+ if ( blksize_size[major] != NULL )
+ {
+ kfree(blksize_size[major]);
+ blksize_size[major] = NULL;
+ }
+
+ if ( hardsect_size[major] != NULL )
+ {
+ kfree(hardsect_size[major]);
+ hardsect_size[major] = NULL;
+ }
+
+ if ( max_sectors[major] != NULL )
+ {
+ kfree(max_sectors[major]);
+ max_sectors[major] = NULL;
+ }
+
+ (void)unregister_blkdev(major, XLIDE_MAJOR_NAME);
+}
+
+void xlide_cleanup(void)
+{
+ if ( xlide_gendisk[0] == NULL ) return;
+ xlide_gendisk[0] = NULL;
+ cleanup_major(XLIDE_MAJOR_0);
+ cleanup_major(XLIDE_MAJOR_1);
+}
+
--- /dev/null
+/******************************************************************************
+ * xl_scsi.c
+ *
+ * Xenolinux virtual SCSI block-device driver.
+ */
+
+#include "xl_block.h"
+
+#define MAJOR_NR XLSCSI_MAJOR
+#include <linux/blk.h>
+
+#define XLSCSI_MAX 256
+#define XLSCSI_MAJOR_NAME "sd"
+static int xlscsi_blksize_size[XLSCSI_MAX];
+static int xlscsi_hardsect_size[XLSCSI_MAX];
+static int xlscsi_max_sectors[XLSCSI_MAX];
+
+struct gendisk *xlscsi_gendisk = NULL;
+
+static struct block_device_operations xlscsi_block_fops =
+{
+ open: xenolinux_block_open,
+ release: xenolinux_block_release,
+ ioctl: xenolinux_block_ioctl,
+ check_media_change: xenolinux_block_check,
+ revalidate: xenolinux_block_revalidate,
+};
+
+
+/* tiny inteface fn */
+int xlscsi_hwsect(int minor)
+{
+ return xlscsi_hardsect_size[minor];
+}
+
+
+int xlscsi_init(xen_disk_info_t *xdi)
+{
+ int i, result, units, minors, disk;
+ struct gendisk *gd;
+
+ /* If we don't have any usable SCSI devices we may as well bail now. */
+ units = 0;
+ for ( i = 0; i < xdi->count; i++ )
+ if ( IS_SCSI_XENDEV(xdi->disks[i].device) &&
+ ((xdi->disks[i].device & XENDEV_IDX_MASK) <
+ XLSCSI_DEVS_PER_MAJOR) )
+ units++;
+ if ( units == 0 ) return 0;
+
+ SET_MODULE_OWNER(&xlscsi_block_fops);
+
+ result = register_blkdev(XLSCSI_MAJOR, XLSCSI_MAJOR_NAME,
+ &xlscsi_block_fops);
+ if ( result < 0 )
+ {
+ printk (KERN_ALERT "XL SCSI: can't get major %d\n", XLSCSI_MAJOR);
+ return result;
+ }
+
+ /* Initialize global arrays. */
+ for ( i = 0; i < XLSCSI_MAX; i++ )
+ {
+ xlscsi_blksize_size[i] = 1024; //XXX 512;
+ xlscsi_hardsect_size[i] = 512;
+ xlscsi_max_sectors[i] = 128*8; //XXX 128
+ }
+
+ blk_size[XLSCSI_MAJOR] = NULL;
+ blksize_size[XLSCSI_MAJOR] = xlscsi_blksize_size;
+ hardsect_size[XLSCSI_MAJOR] = xlscsi_hardsect_size;
+ max_sectors[XLSCSI_MAJOR] = xlscsi_max_sectors;
+ read_ahead[XLSCSI_MAJOR] = NULL; //XXX8;
+
+ blk_init_queue(BLK_DEFAULT_QUEUE(XLSCSI_MAJOR), do_xlblk_request);
+
+ /*
+ * Turn off barking 'headactive' mode. We dequeue buffer heads as
+ * soon as we pass them down to Xen.
+ */
+ blk_queue_headactive(BLK_DEFAULT_QUEUE(XLSCSI_MAJOR), 0);
+
+ units = XLSCSI_MAX >> XLSCSI_PARTN_SHIFT;
+
+ /* Construct an appropriate gendisk structure. */
+ minors = units * (1<<XLSCSI_PARTN_SHIFT);
+ gd = kmalloc(sizeof(struct gendisk), GFP_KERNEL);
+ gd->sizes = kmalloc(minors * sizeof(int), GFP_KERNEL);
+ gd->part = kmalloc(minors * sizeof(struct hd_struct), GFP_KERNEL);
+ gd->major = XLSCSI_MAJOR;
+ gd->major_name = XLSCSI_MAJOR_NAME;
+ gd->minor_shift = XLSCSI_PARTN_SHIFT;
+ gd->max_p = 1<<XLSCSI_PARTN_SHIFT;
+ gd->nr_real = units;
+ gd->real_devices = kmalloc(units * sizeof(xl_disk_t), GFP_KERNEL);
+ gd->next = NULL;
+ gd->fops = &xlscsi_block_fops;
+ gd->de_arr = kmalloc(sizeof(*gd->de_arr) * units, GFP_KERNEL);
+ gd->flags = kmalloc(sizeof(*gd->flags) * units, GFP_KERNEL);
+ memset(gd->sizes, 0, minors * sizeof(int));
+ memset(gd->part, 0, minors * sizeof(struct hd_struct));
+ memset(gd->de_arr, 0, sizeof(*gd->de_arr) * units);
+ memset(gd->flags, 0, sizeof(*gd->flags) * units);
+ memset(gd->real_devices, 0, sizeof(xl_disk_t) * units);
+ xlscsi_gendisk = gd;
+ add_gendisk(gd);
+
+ /* Now register each disk in turn. */
+ for ( i = 0; i < xdi->count; i++ )
+ {
+ disk = xdi->disks[i].device & XENDEV_IDX_MASK;
+
+ if ( !IS_SCSI_XENDEV(xdi->disks[i].device) ||
+ (disk >= XLSCSI_DEVS_PER_MAJOR) )
+ continue;
+
+ ((xl_disk_t *)gd->real_devices)[disk].capacity =
+ xdi->disks[i].capacity;
+ register_disk(gd,
+ MKDEV(XLSCSI_MAJOR, disk<<XLSCSI_PARTN_SHIFT),
+ 1<<XLSCSI_PARTN_SHIFT,
+ &xlscsi_block_fops,
+ xdi->disks[i].capacity);
+ }
+
+ printk(KERN_ALERT
+ "XenoLinux Virtual SCSI Device Driver installed [device: %d]\n",
+ XLSCSI_MAJOR);
+
+ return 0;
+}
+
+
+void xlscsi_cleanup(void)
+{
+ if ( xlscsi_gendisk == NULL ) return;
+
+ blk_cleanup_queue(BLK_DEFAULT_QUEUE(XLSCSI_MAJOR));
+
+ xlscsi_gendisk = NULL;
+
+ read_ahead[XLSCSI_MAJOR] = 0;
+
+ if ( blksize_size[XLSCSI_MAJOR] != NULL )
+ {
+ kfree(blksize_size[XLSCSI_MAJOR]);
+ blksize_size[XLSCSI_MAJOR] = NULL;
+ }
+
+ if ( hardsect_size[XLSCSI_MAJOR] != NULL )
+ {
+ kfree(hardsect_size[XLSCSI_MAJOR]);
+ hardsect_size[XLSCSI_MAJOR] = NULL;
+ }
+
+ if ( max_sectors[XLSCSI_MAJOR] != NULL )
+ {
+ kfree(max_sectors[XLSCSI_MAJOR]);
+ max_sectors[XLSCSI_MAJOR] = NULL;
+ }
+
+ if ( unregister_blkdev(XLSCSI_MAJOR, XLSCSI_MAJOR_NAME) != 0 )
+ {
+ printk(KERN_ALERT
+ "XenoLinux Virtual SCSI Device Driver uninstalled w/ errs\n");
+ }
+}
+
--- /dev/null
+/******************************************************************************
+ * xl_segment.c
+ *
+ * Xenolinux virtual block-device driver (xvd).
+ *
+ */
+
+#include "xl_block.h"
+
+#define MAJOR_NR XLVIRT_MAJOR
+#include <linux/blk.h>
+
+/* Copied from linux/ide.h */
+typedef unsigned char byte;
+
+#define XLVIRT_MAX 256
+#define XLVIRT_MAJOR_NAME "xvd"
+static int xlseg_blksize_size[XLVIRT_MAX];
+static int xlseg_hardsect_size[XLVIRT_MAX];
+static int xlseg_max_sectors[XLVIRT_MAX];
+
+struct gendisk *xlsegment_gendisk = NULL;
+
+static xen_disk_info_t xlseg_disk_info;
+
+static struct block_device_operations xlsegment_block_fops =
+{
+ open: xenolinux_block_open,
+ release: xenolinux_block_release,
+ ioctl: xenolinux_block_ioctl,
+ check_media_change: xenolinux_block_check,
+ revalidate: xenolinux_block_revalidate,
+};
+
+
+int xlsegment_hwsect(int minor)
+{
+ return xlseg_hardsect_size[minor];
+}
+
+
+int __init xlseg_init(void)
+{
+ int i, result, units, minors, disk;
+ xen_disk_info_t *xdi = &xlseg_disk_info;
+ struct gendisk *gd;
+
+ SET_MODULE_OWNER(&xlsegment_block_fops);
+
+ /* Probe for disk information. */
+ memset(xdi, 0, sizeof(*xdi));
+ xenolinux_control_msg(XEN_BLOCK_PROBE_SEG, (char *)xdi, sizeof(*xdi));
+
+ DPRINTK("xvd block device probe:\n");
+ for ( i = 0; i < xdi->count; i++ )
+ {
+ DPRINTK(" %2d: device: %d, capacity: %ld\n",
+ i, xdi->disks[i].device, xdi->disks[i].capacity);
+ }
+
+ result = register_blkdev(XLVIRT_MAJOR, XLVIRT_MAJOR_NAME,
+ &xlsegment_block_fops);
+ if ( result < 0 )
+ {
+ printk(KERN_ALERT "XL Segment: can't get major %d\n", XLVIRT_MAJOR);
+ return result;
+ }
+
+ /* Initialize global arrays. */
+ for (i = 0; i < XLVIRT_MAX; i++)
+ {
+ xlseg_blksize_size[i] = 512;
+ xlseg_hardsect_size[i] = 512;
+ xlseg_max_sectors[i] = 128;
+ }
+
+ blk_size[XLVIRT_MAJOR] = NULL;
+ blksize_size[XLVIRT_MAJOR] = xlseg_blksize_size;
+ hardsect_size[XLVIRT_MAJOR] = xlseg_hardsect_size;
+ max_sectors[XLVIRT_MAJOR] = xlseg_max_sectors;
+ read_ahead[XLVIRT_MAJOR] = 8;
+
+ blk_init_queue(BLK_DEFAULT_QUEUE(XLVIRT_MAJOR), do_xlblk_request);
+
+ /*
+ * Turn off barking 'headactive' mode. We dequeue buffer heads as
+ * soon as we pass them down to Xen.
+ */
+ blk_queue_headactive(BLK_DEFAULT_QUEUE(XLVIRT_MAJOR), 0);
+
+ units = XLVIRT_MAX >> XLVIRT_PARTN_SHIFT;
+
+ /* Construct an appropriate gendisk structure. */
+ minors = units * (1<<XLVIRT_PARTN_SHIFT);
+ gd = kmalloc(sizeof(struct gendisk), GFP_KERNEL);
+ gd->sizes = kmalloc(minors * sizeof(int), GFP_KERNEL);
+ gd->part = kmalloc(minors * sizeof(struct hd_struct), GFP_KERNEL);
+ gd->major = XLVIRT_MAJOR;
+ gd->major_name = XLVIRT_MAJOR_NAME;
+ gd->minor_shift = XLVIRT_PARTN_SHIFT;
+ gd->max_p = 1<<XLVIRT_PARTN_SHIFT;
+ gd->nr_real = units;
+ gd->real_devices = kmalloc(units * sizeof(xl_disk_t), GFP_KERNEL);
+ gd->next = NULL;
+ gd->fops = &xlsegment_block_fops;
+ gd->de_arr = kmalloc(sizeof(*gd->de_arr) * units, GFP_KERNEL);
+ gd->flags = kmalloc(sizeof(*gd->flags) * units, GFP_KERNEL);
+ memset(gd->sizes, 0, minors * sizeof(int));
+ memset(gd->part, 0, minors * sizeof(struct hd_struct));
+ memset(gd->de_arr, 0, sizeof(*gd->de_arr) * units);
+ memset(gd->flags, 0, sizeof(*gd->flags) * units);
+ memset(gd->real_devices, 0, sizeof(xl_disk_t) * units);
+ xlsegment_gendisk = gd;
+ add_gendisk(gd);
+
+ /* Now register each disk in turn. */
+ for ( i = 0; i < xdi->count; i++ )
+ {
+ disk = xdi->disks[i].device & XENDEV_IDX_MASK;
+
+ if ( !IS_VIRTUAL_XENDEV(xdi->disks[i].device) ||
+ (disk >= XLVIRT_DEVS_PER_MAJOR) )
+ continue;
+
+ ((xl_disk_t *)gd->real_devices)[disk].capacity =
+ xdi->disks[i].capacity;
+ register_disk(gd,
+ MKDEV(XLVIRT_MAJOR, disk<<XLVIRT_PARTN_SHIFT),
+ 1<<XLVIRT_PARTN_SHIFT,
+ &xlsegment_block_fops,
+ xdi->disks[i].capacity);
+ }
+
+ printk(KERN_ALERT
+ "XenoLinux Virtual Segment Device Driver installed [device: %d]\n",
+ XLVIRT_MAJOR);
+
+ return 0;
+}
+
+
+static void __exit xlseg_cleanup(void)
+{
+ if ( xlsegment_gendisk == NULL ) return;
+
+ blk_cleanup_queue(BLK_DEFAULT_QUEUE(XLVIRT_MAJOR));
+
+ xlsegment_gendisk = NULL;
+
+ read_ahead[XLVIRT_MAJOR] = 0;
+
+ if ( blksize_size[XLVIRT_MAJOR] != NULL )
+ {
+ kfree(blksize_size[XLVIRT_MAJOR]);
+ blksize_size[XLVIRT_MAJOR] = NULL;
+ }
+
+ if ( hardsect_size[XLVIRT_MAJOR] != NULL )
+ {
+ kfree(hardsect_size[XLVIRT_MAJOR]);
+ hardsect_size[XLVIRT_MAJOR] = NULL;
+ }
+
+ if ( max_sectors[XLVIRT_MAJOR] != NULL )
+ {
+ kfree(max_sectors[XLVIRT_MAJOR]);
+ max_sectors[XLVIRT_MAJOR] = NULL;
+ }
+
+ if ( unregister_blkdev(XLVIRT_MAJOR, XLVIRT_MAJOR_NAME) != 0 )
+ {
+ printk(KERN_ALERT
+ "XenoLinux Virtual Segment Device Driver"
+ " uninstalled w/ errs\n");
+ }
+}
+
+
+#ifdef MODULE
+module_init(xlseg_init);
+module_exit(xlseg_cleanup);
+#endif
--- /dev/null
+/*
+ * xl_segment_proc.c
+ *
+ * XenoLinux virtual disk proc interface .
+ */
+
+#include "xl_block.h"
+#include <linux/proc_fs.h>
+#include <linux/delay.h>
+
+static struct proc_dir_entry *vhd;
+
+static int proc_read_vhd(char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ return 0;
+}
+
+#define isdelim(c) \
+ (c==' '||c==','||c=='\n'||c=='\r'||c=='\t'||c==':'||c=='('||c==')' ? 1 : 0)
+
+char *get_string(char *string) /* a bit like strtok */
+{
+ static char *temp;
+ int loop = 0;
+
+ if (string != NULL)
+ temp = string;
+ else
+ string = temp;
+
+ try_again:
+
+ while (!isdelim(string[loop]))
+ {
+ if (string[loop] == '\0')
+ return NULL;
+ loop++;
+ }
+
+ string[loop] = '\0';
+ temp = (string + loop + 1);
+
+ if (loop == 0)
+ {
+ string = temp;
+ goto try_again;
+ }
+
+ return string;
+}
+
+
+#define isdigit(c) (c >= '0' && c <= '9' ? 1 : 0)
+unsigned long to_number(char *string) /* atoi */
+{
+ unsigned long value = 0;
+
+ if (string == NULL) return 0;
+
+ while (!isdigit(*string) && *string != '\0') string++;
+
+ while (isdigit(*string))
+ {
+ value = value * 10 + (*string - '0');
+ string++;
+ }
+
+ return value;
+}
+
+static int proc_write_vhd(struct file *file, const char *buffer,
+ unsigned long count, void *data)
+{
+ char *local = kmalloc((count + 1) * sizeof(char), GFP_KERNEL);
+ char *string;
+ int loop;
+ xv_disk_t xvd;
+
+ memset (&xvd, 0, sizeof(xvd));
+
+ if (copy_from_user(local, buffer, count))
+ {
+ return -EFAULT;
+ }
+ local[count] = '\0';
+
+ string = get_string(local); /* domain specifier */
+ if (string == NULL)
+ {
+ return count;
+ }
+ if (*string != 'd' && *string != 'D')
+ {
+ printk (KERN_ALERT
+ "error: domain specifier missing [%s]. should be \"domain\".\n",
+ string);
+ return count;
+ }
+
+ string = get_string(NULL); /* domain number */
+ if (string == NULL)
+ {
+ printk (KERN_ALERT "error: domain number missing\n");
+ return count;
+ }
+ xvd.domain = (int) to_number(string);
+
+ string = get_string(NULL);
+ if (string && (strcmp(string, "RO") == 0 || strcmp(string, "ro") == 0))
+ {
+ xvd.mode = XEN_DISK_READ_ONLY;
+ }
+ else if (string && (strcmp(string, "RW") == 0 || strcmp(string, "rw") == 0))
+ {
+ xvd.mode = XEN_DISK_READ_WRITE;
+ }
+ else
+ {
+ printk (KERN_ALERT
+ "error: bad mode [%s]. should be \"rw\" or \"ro\".\n",
+ string);
+ return count;
+ }
+
+ string = get_string(NULL); /* look for Segment */
+ if (string == NULL || (*string != 's' && *string != 'S'))
+ {
+ printk (KERN_ALERT
+ "error: segment specifier missing [%s]. should be \"segment\".\n",
+ string);
+ return count;
+ }
+
+ string = get_string(NULL); /* segment number */
+ if (string == NULL)
+ {
+ printk (KERN_ALERT "error: segment number missing\n");
+ return count;
+ }
+ xvd.segment = (int) to_number(string);
+
+ string = get_string(NULL); /* look for Extents */
+ if (string == NULL || (*string != 'e' && *string != 'E'))
+ {
+ printk (KERN_ALERT
+ "error: extents specifier missing [%s]. should be \"extents\".\n",
+ string);
+ return count;
+ }
+
+ string = get_string(NULL); /* number of extents */
+ if (string == NULL)
+ {
+ printk (KERN_ALERT "error: number of extents missing\n");
+ return count;
+ }
+ xvd.ext_count = (int) to_number(string);
+
+ /* ignore parenthesis */
+
+ for (loop = 0; loop < xvd.ext_count; loop++)
+ {
+ string = get_string(NULL); /* look for Disk */
+ if (string == NULL || (*string != 'd' && *string != 'D'))
+ {
+ printk (KERN_ALERT
+ "hmm, extent disk specifier missing [%s]. should be \"disk\".\n",
+ string);
+ return count;
+ }
+ string = get_string(NULL); /* disk number */
+ if (string == NULL)
+ {
+ printk (KERN_ALERT "error: disk number missing\n");
+ return count;
+ }
+ xvd.extents[loop].disk = xldev_to_physdev((int) to_number(string));
+
+ string = get_string(NULL); /* look for Offset */
+ if (string == NULL || (*string != 'o' && *string != 'O'))
+ {
+ printk (KERN_ALERT
+ "error: disk offset missing [%s]. should be \"offset\".\n",
+ string);
+ return count;
+ }
+ string = get_string(NULL); /* offset */
+ if (string == NULL)
+ {
+ printk (KERN_ALERT "error: offset missing\n");
+ return count;
+ }
+ xvd.extents[loop].offset = to_number(string);
+
+ string = get_string(NULL); /* look for Size */
+ if (string == NULL || (*string != 's' && *string != 'S'))
+ {
+ printk (KERN_ALERT
+ "error: extent size missing [%s]. should be \"size\".\n",
+ string);
+ return count;
+ }
+ string = get_string(NULL); /* size */
+ if (string == NULL)
+ {
+ printk (KERN_ALERT "error: extent size missing\n");
+ return count;
+ }
+ xvd.extents[loop].size = to_number(string);
+ }
+
+ xenolinux_control_msg(XEN_BLOCK_SEG_CREATE, (char *)&xvd, sizeof(xvd));
+
+ return count;
+}
+
+/******************************************************************/
+
+int __init xlseg_proc_init(void)
+{
+ vhd = create_proc_entry("xeno/dom0/vhd", 0644, NULL);
+ if (vhd == NULL)
+ {
+ panic ("xlseg_init: unable to create vhd proc entry\n");
+ }
+ vhd->data = NULL;
+ vhd->read_proc = proc_read_vhd;
+ vhd->write_proc = proc_write_vhd;
+ vhd->owner = THIS_MODULE;
+
+ printk(KERN_ALERT "XenoLinux Virtual Disk Device Monitor installed\n");
+ return 0;
+}
+
+static void __exit xlseg_proc_cleanup(void)
+{
+ printk(KERN_ALERT "XenoLinux Virtual Disk Device Monitor uninstalled\n");
+}
+
+#ifdef MODULE
+module_init(xlseg_proc_init);
+module_exit(xlseg_proc_cleanup);
+#endif
--- /dev/null
+O_TARGET := con.o
+obj-$(CONFIG_XEN_CONSOLE) := console.o
+include $(TOPDIR)/Rules.make
--- /dev/null
+/******************************************************************************
+ * console.c
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/serial.h>
+#include <linux/major.h>
+#include <linux/ptrace.h>
+#include <linux/ioport.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/console.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/uaccess.h>
+#include <asm/hypervisor.h>
+
+#define XENO_TTY_MINOR 123
+
+/******************** Kernel console driver ********************************/
+
+static void xen_console_write(struct console *co, const char *s, unsigned count)
+{
+#define STRLEN 256
+ static char str[STRLEN];
+ static int pos = 0;
+ int len;
+
+ /* We buffer output until we see a newline, or until the buffer is full. */
+ while ( count != 0 )
+ {
+ len = ((STRLEN - pos) > count) ? count : STRLEN - pos;
+ memcpy(str + pos, s, len);
+ pos += len;
+ s += len;
+ count -= len;
+ if ( (pos == STRLEN) || (str[pos-1] == '\n') )
+ {
+ (void)HYPERVISOR_console_write(str, pos);
+ pos = 0;
+ }
+ }
+}
+
+static kdev_t xen_console_device(struct console *c)
+{
+ /*
+ * This is the magic that binds our "struct console" to our
+ * "tty_struct", defined below.
+ */
+ return MKDEV(TTY_MAJOR, XENO_TTY_MINOR);
+}
+
+static struct console xen_console_info = {
+ name: "xen_console",
+ write: xen_console_write,
+ device: xen_console_device,
+ flags: CON_PRINTBUFFER,
+ index: -1,
+};
+
+void xen_console_init(void)
+{
+ register_console(&xen_console_info);
+}
+
+
+/******************** Initial /dev/console *********************************/
+
+
+static struct tty_driver xeno_console_driver;
+static int xeno_console_refcount;
+static struct tty_struct *xeno_console_table[1];
+static struct termios *xeno_console_termios[1];
+static struct termios *xeno_console_termios_locked[1];
+
+static int xeno_console_write_room(struct tty_struct *tty)
+{
+ return INT_MAX;
+}
+
+static int xeno_console_chars_in_buffer(struct tty_struct *tty)
+{
+ return 0;
+}
+
+static inline int xeno_console_xmit(int ch)
+{
+ char _ch = ch;
+ xen_console_write(NULL, &_ch, 1);
+ return 1;
+}
+
+static int xeno_console_write(struct tty_struct *tty, int from_user,
+ const u_char * buf, int count)
+{
+ int i;
+
+ if ( from_user && verify_area(VERIFY_READ, buf, count) )
+ {
+ return -EINVAL;
+ }
+
+ for ( i = 0; i < count; i++ )
+ {
+ char ch;
+ if ( from_user )
+ {
+ __get_user(ch, buf + i);
+ }
+ else
+ {
+ ch = buf[i];
+ }
+ xeno_console_xmit(ch);
+ }
+ return i;
+}
+
+static void xeno_console_put_char(struct tty_struct *tty, u_char ch)
+{
+ xeno_console_xmit(ch);
+}
+
+static int xeno_console_open(struct tty_struct *tty, struct file *filp)
+{
+ int line;
+
+ MOD_INC_USE_COUNT;
+ line = MINOR(tty->device) - tty->driver.minor_start;
+ if ( line )
+ {
+ MOD_DEC_USE_COUNT;
+ return -ENODEV;
+ }
+
+ tty->driver_data = NULL;
+
+ return 0;
+}
+
+static void xeno_console_close(struct tty_struct *tty, struct file *filp)
+{
+ MOD_DEC_USE_COUNT;
+}
+
+int __init xeno_con_init(void)
+{
+ memset(&xeno_console_driver, 0, sizeof(struct tty_driver));
+ xeno_console_driver.magic = TTY_DRIVER_MAGIC;
+ xeno_console_driver.driver_name = "xeno_console";
+ xeno_console_driver.name = "xencon";
+ xeno_console_driver.major = TTY_MAJOR;
+ xeno_console_driver.minor_start = XENO_TTY_MINOR;
+ xeno_console_driver.num = 1;
+ xeno_console_driver.type = TTY_DRIVER_TYPE_SERIAL;
+ xeno_console_driver.subtype = SERIAL_TYPE_NORMAL;
+ xeno_console_driver.init_termios = tty_std_termios;
+ xeno_console_driver.flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_NO_DEVFS;
+ xeno_console_driver.refcount = &xeno_console_refcount;
+ xeno_console_driver.table = xeno_console_table;
+ xeno_console_driver.termios = xeno_console_termios;
+ xeno_console_driver.termios_locked = xeno_console_termios_locked;
+ /* Functions */
+ xeno_console_driver.open = xeno_console_open;
+ xeno_console_driver.close = xeno_console_close;
+ xeno_console_driver.write = xeno_console_write;
+ xeno_console_driver.write_room = xeno_console_write_room;
+ xeno_console_driver.put_char = xeno_console_put_char;
+ xeno_console_driver.chars_in_buffer = xeno_console_chars_in_buffer;
+
+ if ( tty_register_driver(&xeno_console_driver) )
+ {
+ printk(KERN_ERR "Couldn't register Xeno console driver\n");
+ }
+ else
+ {
+ printk("Xeno console successfully installed\n");
+ }
+
+ return 0;
+}
+
+void __exit xeno_con_fini(void)
+{
+ int ret;
+
+ ret = tty_unregister_driver(&xeno_console_driver);
+ if ( ret != 0 )
+ {
+ printk(KERN_ERR "Unable to unregister Xeno console driver: %d\n", ret);
+ }
+}
+
+module_init(xeno_con_init);
+module_exit(xeno_con_fini);
+
--- /dev/null
+O_TARGET := dom0.o
+obj-y := dom0_memory.o dom0_core.o vfr.o sched_ops.o
+include $(TOPDIR)/Rules.make
--- /dev/null
+/*
+ * domain 0 block driver interface
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+
+static int __init init_module(void)
+{
+ request_module("xl_block");
+ printk("Successfully installed domain 0 block interface\n");
+
+
+ return 0;
+}
+
+static void __exit cleanup_module(void)
+{
+ printk("Successfully de-installed domain-0 block interface\n");
+ return 0;
+}
+
+module_init(init_module);
+module_exit(cleanup_module);
--- /dev/null
+/******************************************************************************
+ * dom0_core.c
+ *
+ * Interface to privileged domain-0 commands.
+ *
+ * Copyright (c) 2002, K A Fraser, B Dragovic
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/proc_fs.h>
+
+#include <linux/mm.h>
+#include <linux/mman.h>
+#include <linux/swap.h>
+#include <linux/smp_lock.h>
+#include <linux/swapctl.h>
+#include <linux/iobuf.h>
+#include <linux/highmem.h>
+#include <linux/pagemap.h>
+#include <linux/seq_file.h>
+
+#include <asm/pgalloc.h>
+#include <asm/pgtable.h>
+#include <asm/uaccess.h>
+#include <asm/tlb.h>
+
+#include "dom0_ops.h"
+
+#define TRUE 1
+#define FALSE 0
+
+/* Private proc-file data structures. */
+typedef struct proc_data {
+ unsigned int domain;
+ unsigned long map_size;
+} dom_procdata_t;
+
+typedef struct proc_mem_data {
+ unsigned long pfn;
+ int tot_pages;
+} proc_memdata_t;
+
+#define XENO_BASE "xeno"
+#define DOM0_CMD_INTF "dom0_cmd"
+#define DOM0_NEWDOM "new_dom_data"
+#define DOM_LIST_INTF "domains"
+
+#define MAX_LEN 16
+#define DOM_DIR "dom"
+#define DOM_MEM "mem"
+#define DOM_VIF "vif"
+#define DOM_USAGE "usage"
+
+#define MAP_DISCONT 1
+
+struct proc_dir_entry *xeno_base;
+static struct proc_dir_entry *dom0_cmd_intf;
+static struct proc_dir_entry *proc_ft;
+static struct proc_dir_entry *dom_list_intf;
+
+unsigned long direct_mmap(unsigned long, unsigned long, pgprot_t, int, int);
+int direct_unmap(unsigned long, unsigned long);
+int direct_disc_unmap(unsigned long, unsigned long, int);
+
+static unsigned char readbuf[1204];
+
+static int cmd_read_proc(char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ strcpy(page, readbuf);
+ *readbuf = '\0';
+ *eof = 1;
+ *start = page;
+ return strlen(page);
+}
+
+static ssize_t dom_vif_read(struct file * file, char * buff, size_t size, loff_t * off)
+{
+ int hyp_buf[32];
+ char buf[128];
+ network_op_t op;
+ static int finished = 0;
+
+ if ( finished )
+ {
+ finished = 0;
+ return 0;
+ }
+
+ op.cmd = NETWORK_OP_VIFQUERY;
+ op.u.vif_query.domain = (unsigned int)
+ ((struct proc_dir_entry *)file->f_dentry->d_inode->u.generic_ip)->data;
+ op.u.vif_query.buf = hyp_buf;
+
+ (void) HYPERVISOR_network_op(&op);
+
+ if(hyp_buf[0] < 0) {
+ strcpy(buf, "Error getting domain's vif list from hypervisor.\n");
+ } else {
+ int i;
+ int len = 0;
+ strcpy(buf, "No vif found");
+
+ for(i = 1; i <= hyp_buf[0] && len < 127; i++)
+ len += snprintf(buf + len, 127 - len, "%d\n", hyp_buf[i]);
+ }
+
+ if (*off >= (strlen(buf)+1)) return 0;
+
+ copy_to_user(buff, buf, strlen(buf));
+
+ finished = 1;
+
+ return strlen(buf)+1;
+}
+
+struct file_operations dom_vif_ops = {
+ read: dom_vif_read
+};
+
+static ssize_t dom_usage_read(struct file * file, char * buff, size_t size, loff_t * off)
+{
+ char str[256];
+ int vifs[32];
+ dom0_op_t op;
+ network_op_t netop;
+ int i, end;
+ unsigned int domain;
+ static int finished = 0;
+
+ if ( finished )
+ {
+ finished = 0;
+ return 0;
+ }
+
+ domain = (unsigned int)
+ ((struct proc_dir_entry *)file->f_dentry->d_inode->u.generic_ip)->data;
+ op.cmd = DOM0_GETDOMAININFO;
+
+ op.u.getdominfo.domain = domain;
+
+ (void) HYPERVISOR_dom0_op(&op);
+
+ end = snprintf(str, 256, "cpu: %lld\n", op.u.getdominfo.cpu_time);
+
+ netop.cmd = NETWORK_OP_VIFQUERY;
+ netop.u.vif_query.domain = domain;
+ netop.u.vif_query.buf = vifs;
+
+ (void) HYPERVISOR_network_op(&netop);
+
+ for(i = 1; i <= vifs[0]; i++) {
+ netop.cmd = NETWORK_OP_VIFGETINFO;
+ netop.u.vif_getinfo.domain = domain;
+ netop.u.vif_getinfo.vif = vifs[i];
+
+ (void) HYPERVISOR_network_op(&netop);
+
+ end += snprintf(str + end, 255 - end,
+ "vif%d: sent %lld bytes (%lld packets) "
+ "received %lld bytes (%lld packets)\n",
+ vifs[i],
+ netop.u.vif_getinfo.total_bytes_sent,
+ netop.u.vif_getinfo.total_packets_sent,
+ netop.u.vif_getinfo.total_bytes_received,
+ netop.u.vif_getinfo.total_packets_received);
+ }
+
+ if (*off >= end + 1) return 0;
+
+ copy_to_user(buff, str, end);
+
+ finished = 1;
+
+ return end + 1;
+}
+
+struct file_operations dom_usage_ops = {
+ read: dom_usage_read
+};
+
+
+static void create_proc_dom_entries(int dom)
+{
+ struct proc_dir_entry * dir;
+ dom_procdata_t * dom_data;
+ char dir_name[MAX_LEN];
+ struct proc_dir_entry * file;
+
+ snprintf(dir_name, MAX_LEN, "%s%d", DOM_DIR, dom);
+
+ dom_data = (dom_procdata_t *)kmalloc(sizeof(dom_procdata_t), GFP_KERNEL);
+ dom_data->domain = dom;
+
+ dir = proc_mkdir(dir_name, xeno_base);
+ dir->data = dom_data;
+
+ file = create_proc_entry(DOM_VIF, 0600, dir);
+ if (file != NULL)
+ {
+ file->owner = THIS_MODULE;
+ file->nlink = 1;
+ file->proc_fops = &dom_vif_ops;
+ file->data = (void *) dom;
+ }
+
+ file = create_proc_entry(DOM_USAGE, 0600, dir);
+ if (file != NULL)
+ {
+ file->owner = THIS_MODULE;
+ file->nlink = 1;
+ file->proc_fops = &dom_usage_ops;
+ file->data = (void *) dom;
+ }
+}
+
+static ssize_t dom_mem_write(struct file * file, const char * buff,
+ size_t size , loff_t * off)
+{
+ dom_mem_t mem_data;
+
+ copy_from_user(&mem_data, (dom_mem_t *)buff, sizeof(dom_mem_t));
+
+ if(direct_disc_unmap(mem_data.vaddr, mem_data.start_pfn,
+ mem_data.tot_pages) == 0){
+ return sizeof(sizeof(dom_mem_t));
+ } else {
+ return -1;
+ }
+}
+
+static ssize_t dom_mem_read(struct file * file, char * buff, size_t size, loff_t * off)
+{
+ unsigned long addr;
+ pgprot_t prot;
+
+ proc_memdata_t * mem_data = (proc_memdata_t *)((struct proc_dir_entry *)file->f_dentry->d_inode->u.generic_ip)->data;
+
+ prot = PAGE_SHARED;
+
+ /* remap the range using xen specific routines */
+
+ addr = direct_mmap(mem_data->pfn << PAGE_SHIFT, mem_data->tot_pages << PAGE_SHIFT, prot, MAP_DISCONT, mem_data->tot_pages);
+
+ copy_to_user((unsigned long *)buff, &addr, sizeof(addr));
+
+ return sizeof(addr);
+}
+
+struct file_operations dom_mem_ops = {
+ read: dom_mem_read,
+ write: dom_mem_write,
+};
+
+static int dom_map_mem(unsigned int dom, unsigned long pfn, int tot_pages)
+{
+ int ret = -ENOENT;
+ struct proc_dir_entry * pd = xeno_base->subdir;
+ struct proc_dir_entry * file;
+ proc_memdata_t * memdata;
+
+ while(pd != NULL){
+
+ if((pd->mode & S_IFDIR) && ((dom_procdata_t *)pd->data)->domain == dom){
+
+ /* check if there is already an entry for mem and if so
+ * remove it.
+ */
+ remove_proc_entry(DOM_MEM, pd);
+
+ /* create new entry with parameters describing what to do
+ * when it is mmaped.
+ */
+ file = create_proc_entry(DOM_MEM, 0600, pd);
+ if(file != NULL)
+ {
+ file->owner = THIS_MODULE;
+ file->nlink = 1;
+ file->proc_fops = &dom_mem_ops;
+
+ memdata = (proc_memdata_t *)kmalloc(sizeof(proc_memdata_t), GFP_KERNEL);
+ memdata->pfn = pfn;
+ memdata->tot_pages = tot_pages;
+ file->data = memdata;
+
+ ret = 0;
+ break;
+ }
+
+ ret = -EAGAIN;
+ break;
+ }
+ pd = pd->next;
+ }
+
+ return ret;
+}
+
+/* function used to retrieve data associated with new domain */
+static ssize_t dom_data_read(struct file * file, char * buff, size_t size, loff_t * off)
+{
+ dom0_newdomain_t * dom_data = (dom0_newdomain_t *)
+ ((struct proc_dir_entry *)file->f_dentry->d_inode->u.generic_ip)->data;
+
+ copy_to_user((dom0_newdomain_t *)buff, dom_data, sizeof(dom0_newdomain_t));
+
+ remove_proc_entry(DOM0_NEWDOM, xeno_base);
+
+ kfree(dom_data);
+
+ return sizeof(dom0_newdomain_t);
+}
+
+struct file_operations newdom_data_fops = {
+ read: dom_data_read,
+};
+
+static int cmd_write_proc(struct file *file, const char *buffer,
+ u_long count, void *data)
+{
+ dom0_op_t op;
+ int ret = 0;
+ struct proc_dir_entry * new_dom_id;
+ dom0_newdomain_t * params;
+ int i;
+ unsigned long p;
+
+ copy_from_user(&op, buffer, sizeof(dom0_op_t));
+
+ /* do some sanity checks */
+ if(op.cmd > MAX_CMD){
+ ret = -ENOSYS;
+ goto out;
+ }
+
+ if ( op.cmd == MAP_DOM_MEM )
+ {
+ ret = dom_map_mem(op.u.dommem.domain, op.u.dommem.start_pfn,
+ op.u.dommem.tot_pages);
+ }
+ else if ( op.cmd == DO_PGUPDATES )
+ {
+ ret = HYPERVISOR_pt_update(op.u.pgupdate.pgt_update_arr,
+ op.u.pgupdate.num_pgt_updates);
+ }
+ else
+ {
+ ret = HYPERVISOR_dom0_op(&op);
+
+ /* if new domain created, create proc entries */
+ if(op.cmd == DOM0_CREATEDOMAIN) {
+ create_proc_dom_entries(ret);
+
+ params = (dom0_newdomain_t *)kmalloc(sizeof(dom0_newdomain_t),
+ GFP_KERNEL);
+ params->memory_kb = op.u.newdomain.memory_kb;
+ params->pg_head = op.u.newdomain.pg_head;
+ params->num_vifs = op.u.newdomain.num_vifs;
+ params->domain = op.u.newdomain.domain;
+
+ /* now notify user space of the new domain's id */
+ new_dom_id = create_proc_entry(DOM0_NEWDOM, 0600, xeno_base);
+ if ( new_dom_id != NULL )
+ {
+ new_dom_id->owner = THIS_MODULE;
+ new_dom_id->nlink = 1;
+ new_dom_id->proc_fops = &newdom_data_fops;
+ new_dom_id->data = (void *)params;
+ }
+
+ }
+
+ }
+
+out:
+ return ret;
+
+}
+
+/***********************************************************************
+ *
+ * Implementation of /proc/xeno/domains
+ */
+
+static dom0_op_t proc_domains_op;
+static int proc_domains_finished;
+static rwlock_t proc_xeno_domains_lock = RW_LOCK_UNLOCKED;
+
+static void *xeno_domains_next(struct seq_file *s, void *v, loff_t *pos)
+{
+ int ret;
+
+ if (pos != NULL) { ++ (*pos); }
+ if (!proc_domains_finished) {
+ proc_domains_op.u.getdominfo.domain ++;
+ ret = HYPERVISOR_dom0_op(&proc_domains_op);
+ if (ret < 0) proc_domains_finished = TRUE;
+ }
+
+ return (proc_domains_finished) ? NULL : &proc_domains_op;
+}
+
+static void *xeno_domains_start(struct seq_file *s, loff_t *ppos)
+{
+ loff_t pos = *ppos;
+
+ write_lock (&proc_xeno_domains_lock);
+ proc_domains_op.cmd = DOM0_GETDOMAININFO;
+ proc_domains_op.u.getdominfo.domain = 0;
+ (void)HYPERVISOR_dom0_op(&proc_domains_op);
+ proc_domains_finished = FALSE;
+
+ while (pos > 0) {
+ pos --;
+ xeno_domains_next (s, NULL, NULL);
+ }
+
+ return (proc_domains_finished) ? NULL : &proc_domains_op;
+}
+
+static void xeno_domains_stop(struct seq_file *s, void *v)
+{
+ write_unlock (&proc_xeno_domains_lock);
+}
+
+static int xeno_domains_show(struct seq_file *s, void *v)
+{
+ dom0_op_t *di = v;
+
+ /*
+ * Output one domain's details to dom0.
+ *
+ * If you update this format string then change xi_list to match.
+ */
+
+ seq_printf (s,
+ "%8d %2d %1d %2d %8d %8ld %p %8d %s\n",
+ di -> u.getdominfo.domain,
+ di -> u.getdominfo.processor,
+ di -> u.getdominfo.has_cpu,
+ di -> u.getdominfo.state,
+ di -> u.getdominfo.hyp_events,
+ di -> u.getdominfo.mcu_advance,
+ di -> u.getdominfo.pg_head,
+ di -> u.getdominfo.tot_pages,
+ di -> u.getdominfo.name);
+
+ return 0;
+}
+
+struct seq_operations xeno_domains_op = {
+ .start = xeno_domains_start,
+ .next = xeno_domains_next,
+ .stop = xeno_domains_stop,
+ .show = xeno_domains_show,
+};
+
+static int xeno_domains_open(struct inode *inode, struct file *file)
+{
+ return seq_open(file, &xeno_domains_op);
+}
+
+static struct file_operations proc_xeno_domains_operations = {
+ open: xeno_domains_open,
+ read: seq_read,
+ llseek: seq_lseek,
+ release: seq_release,
+};
+
+/***********************************************************************/
+
+
+
+static int __init init_module(void)
+{
+ /* xeno proc root setup */
+ xeno_base = proc_mkdir(XENO_BASE, &proc_root);
+
+ /* xeno control interface */
+ *readbuf = '\0';
+ dom0_cmd_intf = create_proc_entry (DOM0_CMD_INTF, 0600, xeno_base);
+ if ( dom0_cmd_intf != NULL )
+ {
+ dom0_cmd_intf->owner = THIS_MODULE;
+ dom0_cmd_intf->nlink = 1;
+ dom0_cmd_intf->read_proc = cmd_read_proc;
+ dom0_cmd_intf->write_proc = cmd_write_proc;
+ }
+
+ /* domain list interface */
+ dom_list_intf = create_proc_entry (DOM_LIST_INTF, 0400, xeno_base);
+ if ( dom_list_intf != NULL )
+ {
+ dom_list_intf -> owner = THIS_MODULE;
+ dom_list_intf -> nlink = 1;
+ dom_list_intf -> proc_fops = &proc_xeno_domains_operations;
+ }
+
+ /* set up /proc entries for dom 0 */
+ create_proc_dom_entries(0);
+
+ return 0;
+}
+
+
+static void __exit cleanup_module(void)
+{
+ if ( dom0_cmd_intf == NULL ) return;
+ remove_proc_entry("dom0", &proc_root);
+ dom0_cmd_intf = NULL;
+}
+
+
+module_init(init_module);
+module_exit(cleanup_module);
--- /dev/null
+#include <linux/slab.h>
+#include <linux/mm.h>
+#include <linux/mman.h>
+#include <linux/swap.h>
+#include <linux/smp_lock.h>
+#include <linux/swapctl.h>
+#include <linux/iobuf.h>
+#include <linux/highmem.h>
+#include <linux/pagemap.h>
+#include <linux/list.h>
+
+#include <asm/pgalloc.h>
+#include <asm/uaccess.h>
+#include <asm/tlb.h>
+#include <asm/mmu.h>
+
+#include "dom0_ops.h"
+
+#define MAP_CONT 0
+#define MAP_DISCONT 1
+
+extern struct list_head * find_direct(struct list_head *, unsigned long);
+
+/*
+ * bd240: functions below perform direct mapping to the real physical pages
+ * needed for mapping various hypervisor specific structures needed in dom0
+ * userspace by various management applications such as domain builder etc.
+ */
+
+#define direct_set_pte(pteptr, pteval) queue_l1_entry_update(__pa(pteptr)|PGREQ_UNCHECKED_UPDATE, (pteval).pte_low)
+
+#define direct_pte_clear(pteptr) queue_l1_entry_update(__pa(pteptr)|PGREQ_UNCHECKED_UPDATE, 0)
+
+#define __direct_pte(x) ((pte_t) { (x) } )
+#define __direct_mk_pte(page_nr,pgprot) __direct_pte(((page_nr) << PAGE_SHIFT) | pgprot_val(pgprot))
+#define direct_mk_pte_phys(physpage, pgprot) __direct_mk_pte((physpage) >> PAGE_SHIFT, pgprot)
+
+static inline void forget_pte(pte_t page)
+{
+ if (!pte_none(page)) {
+ printk("forget_pte: old mapping existed!\n");
+ BUG();
+ }
+}
+
+static inline void direct_remappte_range(pte_t * pte, unsigned long address, unsigned long size,
+ unsigned long phys_addr, pgprot_t prot)
+{
+ unsigned long end;
+
+ address &= ~PMD_MASK;
+ end = address + size;
+ if (end > PMD_SIZE)
+ end = PMD_SIZE;
+ do {
+ pte_t oldpage;
+ oldpage = ptep_get_and_clear(pte);
+
+ direct_set_pte(pte, direct_mk_pte_phys(phys_addr, prot));
+
+ forget_pte(oldpage);
+ address += PAGE_SIZE;
+ phys_addr += PAGE_SIZE;
+ pte++;
+ } while (address && (address < end));
+
+}
+
+static inline int direct_remappmd_range(struct mm_struct *mm, pmd_t * pmd, unsigned long address, unsigned long size,
+ unsigned long phys_addr, pgprot_t prot)
+{
+ unsigned long end;
+
+ address &= ~PGDIR_MASK;
+ end = address + size;
+ if (end > PGDIR_SIZE)
+ end = PGDIR_SIZE;
+ phys_addr -= address;
+ do {
+ pte_t * pte = pte_alloc(mm, pmd, address);
+ if (!pte)
+ return -ENOMEM;
+ direct_remappte_range(pte, address, end - address, address + phys_addr, prot);
+ address = (address + PMD_SIZE) & PMD_MASK;
+ pmd++;
+ } while (address && (address < end));
+ return 0;
+}
+
+/* Note: this is only safe if the mm semaphore is held when called. */
+int direct_remap_page_range(unsigned long from, unsigned long phys_addr, unsigned long size, pgprot_t prot)
+{
+ int error = 0;
+ pgd_t * dir;
+ unsigned long beg = from;
+ unsigned long end = from + size;
+ struct mm_struct *mm = current->mm;
+
+ phys_addr -= from;
+ dir = pgd_offset(mm, from);
+ flush_cache_range(mm, beg, end);
+ if (from >= end)
+ BUG();
+
+ spin_lock(&mm->page_table_lock);
+ do {
+ pmd_t *pmd = pmd_alloc(mm, dir, from);
+ error = -ENOMEM;
+ if (!pmd)
+ break;
+ error = direct_remappmd_range(mm, pmd, from, end - from, phys_addr + from, prot);
+ if (error)
+ break;
+ from = (from + PGDIR_SIZE) & PGDIR_MASK;
+ dir++;
+ } while (from && (from < end));
+ spin_unlock(&mm->page_table_lock);
+ flush_tlb_range(mm, beg, end);
+ return error;
+}
+
+/*
+ * used for remapping discontiguous bits of domain's memory, pages to map are
+ * found from frame table beginning at the given first_pg index
+ */
+int direct_remap_disc_page_range(unsigned long from,
+ unsigned long first_pg, int tot_pages, pgprot_t prot)
+{
+ dom0_op_t dom0_op;
+ unsigned long *pfns = get_free_page(GFP_KERNEL);
+ unsigned long start = from;
+ int pages, i;
+
+ while ( tot_pages != 0 )
+ {
+ dom0_op.cmd = DOM0_GETMEMLIST;
+ dom0_op.u.getmemlist.start_pfn = first_pg;
+ pages = 1023;
+ dom0_op.u.getmemlist.num_pfns = 1024;
+ if ( tot_pages < 1024 )
+ dom0_op.u.getmemlist.num_pfns = pages = tot_pages;
+ dom0_op.u.getmemlist.buffer = pfns;
+ (void)HYPERVISOR_dom0_op(&dom0_op);
+ first_pg = pfns[1023];
+
+ for ( i = 0; i < pages; i++ )
+ {
+ if(direct_remap_page_range(start, pfns[i] << PAGE_SHIFT,
+ PAGE_SIZE, prot))
+ goto out;
+ start += PAGE_SIZE;
+ tot_pages--;
+ }
+ }
+
+out:
+ free_page(pfns);
+ return tot_pages;
+}
+
+/* below functions replace standard sys_mmap and sys_munmap which are absolutely useless
+ * for direct memory mapping. direct_zap* functions are minor ammendments to the
+ * original versions in mm/memory.c. the changes are to enable unmapping of real physical
+ * addresses.
+ */
+
+unsigned long direct_mmap(unsigned long phys_addr, unsigned long size,
+ pgprot_t prot, int flag, int tot_pages)
+{
+ direct_mmap_node_t * dmmap;
+ struct list_head * entry;
+ unsigned long addr;
+ int ret = 0;
+
+ if(!capable(CAP_SYS_ADMIN)){
+ ret = -EPERM;
+ goto out;
+ }
+
+ /* get unmapped area invokes xen specific arch_get_unmapped_area */
+ addr = get_unmapped_area(NULL, 0, size, 0, 0);
+ if(addr & ~PAGE_MASK){
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ /* add node on the list of directly mapped areas, make sure the
+ * list remains sorted.
+ */
+ dmmap = (direct_mmap_node_t *)kmalloc(sizeof(direct_mmap_node_t), GFP_KERNEL);
+ dmmap->vm_start = addr;
+ dmmap->vm_end = addr + size;
+ entry = find_direct(¤t->mm->context.direct_list, addr);
+ if(entry != ¤t->mm->context.direct_list){
+ list_add_tail(&dmmap->list, entry);
+ } else {
+ list_add_tail(&dmmap->list, ¤t->mm->context.direct_list);
+ }
+
+ /* and perform the mapping */
+ if(flag == MAP_DISCONT){
+ ret = direct_remap_disc_page_range(addr, phys_addr >> PAGE_SHIFT,
+ tot_pages, prot);
+ } else {
+ ret = direct_remap_page_range(addr, phys_addr, size, prot);
+ }
+
+ if(ret == 0)
+ ret = addr;
+
+out:
+ return ret;
+}
+
+/* most of the checks, refcnt updates, cache stuff have been thrown out as they are not
+ * needed
+ */
+static inline int direct_zap_pte_range(mmu_gather_t *tlb, pmd_t * pmd, unsigned long address,
+ unsigned long size)
+{
+ unsigned long offset;
+ pte_t * ptep;
+ int freed = 0;
+
+ if (pmd_none(*pmd))
+ return 0;
+ if (pmd_bad(*pmd)) {
+ pmd_ERROR(*pmd);
+ pmd_clear(pmd);
+ return 0;
+ }
+ ptep = pte_offset(pmd, address);
+ offset = address & ~PMD_MASK;
+ if (offset + size > PMD_SIZE)
+ size = PMD_SIZE - offset;
+ size &= PAGE_MASK;
+ for (offset=0; offset < size; ptep++, offset += PAGE_SIZE) {
+ pte_t pte = *ptep;
+ if (pte_none(pte))
+ continue;
+ freed ++;
+ direct_pte_clear(ptep);
+ }
+
+ return freed;
+}
+
+static inline int direct_zap_pmd_range(mmu_gather_t *tlb, pgd_t * dir,
+ unsigned long address, unsigned long size)
+{
+ pmd_t * pmd;
+ unsigned long end;
+ int freed;
+
+ if (pgd_none(*dir))
+ return 0;
+ if (pgd_bad(*dir)) {
+ pgd_ERROR(*dir);
+ pgd_clear(dir);
+ return 0;
+ }
+ pmd = pmd_offset(dir, address);
+ end = address + size;
+ if (end > ((address + PGDIR_SIZE) & PGDIR_MASK))
+ end = ((address + PGDIR_SIZE) & PGDIR_MASK);
+ freed = 0;
+ do {
+ freed += direct_zap_pte_range(tlb, pmd, address, end - address);
+ address = (address + PMD_SIZE) & PMD_MASK;
+ pmd++;
+ } while (address < end);
+ return freed;
+}
+
+/*
+ * remove user pages in a given range.
+ */
+void direct_zap_page_range(struct mm_struct *mm, unsigned long address, unsigned long size)
+{
+ mmu_gather_t *tlb;
+ pgd_t * dir;
+ unsigned long start = address, end = address + size;
+ int freed = 0;
+
+ dir = pgd_offset(mm, address);
+
+ /*
+ * This is a long-lived spinlock. That's fine.
+ * There's no contention, because the page table
+ * lock only protects against kswapd anyway, and
+ * even if kswapd happened to be looking at this
+ * process we _want_ it to get stuck.
+ */
+ if (address >= end)
+ BUG();
+ spin_lock(&mm->page_table_lock);
+ flush_cache_range(mm, address, end);
+ tlb = tlb_gather_mmu(mm);
+
+ do {
+ freed += direct_zap_pmd_range(tlb, dir, address, end - address);
+ address = (address + PGDIR_SIZE) & PGDIR_MASK;
+ dir++;
+ } while (address && (address < end));
+
+ /* this will flush any remaining tlb entries */
+ tlb_finish_mmu(tlb, start, end);
+
+ /* decrementing rss removed */
+
+ spin_unlock(&mm->page_table_lock);
+}
+
+int direct_unmap(unsigned long addr, unsigned long size)
+{
+ direct_mmap_node_t * node;
+ struct list_head * curr;
+ struct list_head * direct_list = ¤t->mm->context.direct_list;
+
+ curr = direct_list->next;
+ while(curr != direct_list){
+ node = list_entry(curr, direct_mmap_node_t, list);
+ if(node->vm_start == addr)
+ break;
+ curr = curr->next;
+ }
+
+ if(curr == direct_list)
+ return -1;
+
+ list_del(&node->list);
+ kfree(node);
+
+ direct_zap_page_range(current->mm, addr, size);
+
+ return 0;
+}
+
+int direct_disc_unmap(unsigned long from, unsigned long first_pg, int tot_pages)
+{
+ int count = 0;
+ direct_mmap_node_t * node;
+ struct list_head * curr;
+ struct list_head * direct_list = ¤t->mm->context.direct_list;
+
+ curr = direct_list->next;
+ while(curr != direct_list){
+ node = list_entry(curr, direct_mmap_node_t, list);
+
+ if(node->vm_start == from)
+ break;
+ curr = curr->next;
+ }
+
+ if(curr == direct_list)
+ return -1;
+
+ list_del(&node->list);
+ kfree(node);
+
+ while(count < tot_pages){
+ direct_zap_page_range(current->mm, from, PAGE_SIZE);
+ from += PAGE_SIZE;
+ count++;
+ }
+
+ return 0;
+}
--- /dev/null
+/******************************************************************************
+ * dom0_ops.h
+ *
+ * Process command requests from domain-0 guest OS.
+ * This file includes the Xen part of the interface, plus the extra stuff
+ * that is dealt with by Xenolinux without being handed down to Xen.
+ *
+ * Copyright (c) 2002-2003, K A Fraser, B Dragovic
+ */
+
+#ifndef __DOM0_DOM0_OPS_H__
+#define __DOM0_DOM0_OPS_H__
+
+/* External users of this header file will include Xen's version separately. */
+#ifdef __KERNEL__
+#define NO_DOM0_OP_T
+#include <asm/hypervisor-ifs/dom0_ops.h>
+#endif
+
+/* Extra commands dealt with by Xenolinux. */
+#define MAP_DOM_MEM 14
+#define DO_PGUPDATES 15
+#define MAX_CMD 16
+
+typedef struct dom_mem
+{
+ unsigned int domain;
+ unsigned long vaddr;
+ unsigned long start_pfn;
+ int tot_pages;
+} dom_mem_t;
+
+typedef struct dom_pgupdate
+{
+ unsigned long pgt_update_arr;
+ unsigned long num_pgt_updates;
+} dom_pgupdate_t;
+
+typedef struct dom0_op_st
+{
+ unsigned long cmd;
+ union
+ {
+ dom0_newdomain_t newdomain;
+ dom0_killdomain_t killdomain;
+ dom0_getmemlist_t getmemlist;
+ dom0_bvtctl_t bvtctl;
+ dom0_adjustdom_t adjustdom;
+ dom_mem_t dommem;
+ dom_pgupdate_t pgupdate;
+ dom_meminfo_t meminfo;
+ dom0_getdominfo_t getdominfo;
+ }
+ u;
+} dom0_op_t;
+
+#endif /* __DOM0_DOM0_OPS_H__ */
--- /dev/null
+/* -*- Mode:C; c-basic-offset:4; tab-width:4 -*-
+ ****************************************************************************
+ * (C) 2003 - Rolf Neugebauer - Intel Research Cambridge
+ ****************************************************************************
+ *
+ * File: sched_ops.c
+ * Author: Rolf Neugebauer (neugebar@dcs.gla.ac.uk)
+ * Changes:
+ *
+ * Date: Mar 2003
+ *
+ * Environment: XenoLinux
+ * Description: Dom0 Control interface to scheduler in Xen
+ *
+ * code based on Andy's vfr parsing code
+ *
+ * Commands understood by the interface:
+ *
+ * C <context swith allowance>
+ * S <did> <mcu advance> <warp> <warp limit> <unwarp limit>
+ *
+ ****************************************************************************
+ * $Id: c-insert.c,v 1.7 2002/11/08 16:04:34 rn Exp $
+ ****************************************************************************
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/ctype.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/proc_fs.h>
+
+#include "dom0_ops.h"
+
+#define SCHED_ENTRY "sched"
+extern struct proc_dir_entry *xeno_base;
+static struct proc_dir_entry *sched_pde;
+
+static unsigned char readbuf[1024];
+
+static int sched_read_proc(char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ strcpy(page, readbuf);
+ *readbuf = '\0';
+ *eof = 1;
+ *start = page;
+ return strlen(page);
+}
+
+
+static int sched_write_proc(struct file *file, const char *buffer,
+ u_long count, void *data)
+{
+ dom0_op_t op;
+
+ int ret, len;
+ int ts, te, tl; /* token start, end, and length */
+
+ /* Only admin can adjust scheduling parameters */
+ if ( !capable(CAP_SYS_ADMIN) )
+ return -EPERM;
+
+ /* parse the commands */
+ len = count;
+ ts = te = 0;
+
+ while ( count && isspace(buffer[ts]) ) { ts++; count--; } /*skip spaces*/
+ te = ts;
+ while ( count && !isspace(buffer[te]) ) { te++; count--; } /*command end*/
+ if ( te <= ts ) goto bad;
+ tl = te - ts;
+
+ if ( strncmp(&buffer[ts], "C", tl) == 0 ) {
+ op.cmd = DOM0_BVTCTL;
+ } else if ( strncmp(&buffer[ts], "S", tl) == 0 ) {
+ op.cmd = DOM0_ADJUSTDOM;
+ } else
+ goto bad;
+
+ /* skip whitspaces and get first parameter */
+ ts = te; while ( count && isspace(buffer[ts]) ) { ts++; count--; }
+ te = ts; while ( count && !isspace(buffer[te]) ) { te++; count--; }
+ if ( te <= ts ) goto bad;
+ tl = te - ts;
+ if ( !isdigit(buffer[ts]) ) goto bad;
+
+ if (op.cmd == DOM0_BVTCTL) {
+ /* get context switch allowance */
+ sscanf(&buffer[ts], "%lu", &op.u.bvtctl.ctx_allow);
+ } else if (op.cmd == DOM0_ADJUSTDOM) {
+ sscanf(&buffer[ts], "%u %lu %lu %lu %lu",
+ &op.u.adjustdom.domain,
+ &op.u.adjustdom.mcu_adv,
+ &op.u.adjustdom.warp,
+ &op.u.adjustdom.warpl,
+ &op.u.adjustdom.warpu);
+ }
+ ret = HYPERVISOR_dom0_op(&op);
+ return sizeof(op);
+
+ bad:
+ return -EINVAL;
+
+}
+
+
+/*
+ * main scheduler interface driver driver initialization function.
+ */
+static int __init init_module(void)
+{
+ printk(KERN_ALERT "Starting Domain Scheduler Control Interface\n");
+
+ sched_pde = create_proc_entry(SCHED_ENTRY, 0600, xeno_base);
+ if ( sched_pde == NULL )
+ {
+ printk(KERN_ALERT "Unable to create dom scheduler proc entry!");
+ return -1;
+ }
+
+ sched_pde->read_proc = sched_read_proc;
+ sched_pde->write_proc = sched_write_proc;
+
+ return 0;
+}
+
+static void __exit cleanup_module(void)
+{
+}
+
+module_init(init_module);
+module_exit(cleanup_module);
+
--- /dev/null
+/******************************************************************************
+ * vfr.c
+ *
+ * Interface to the virtual firewall/router.
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/proc_fs.h>
+
+#include <asm/hypervisor-ifs/network.h>
+
+static struct proc_dir_entry *proc_vfr;
+
+static unsigned char readbuf[1024];
+
+/* Helpers, implemented at the bottom. */
+u32 getipaddr(const char *buff, unsigned int len);
+u16 antous(const char *buff, int len);
+int anton(const char *buff, int len);
+
+static int vfr_read_proc(char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ strcpy(page, readbuf);
+ *readbuf = '\0';
+ *eof = 1;
+ *start = page;
+ return strlen(page);
+}
+
+/* The format for the vfr interface is as follows:
+ *
+ * COMMAND <field>=<val> [<field>=<val> [...]]
+ *
+ * where:
+ *
+ * COMMAND = { ACCEPT | COUNT }
+ *
+ * field=val pairs are as follows:
+ *
+ * field = { srcaddr | dstaddr }
+ * val is a dot seperated, numeric IP address.
+ *
+ * field = { srcport | dstport }
+ * val is a (16-bit) unsigned int
+ *
+ * field = { proto }
+ * val = { IP | TCP | UDP | ARP }
+ *
+ */
+
+#define isspace(_x) ( ((_x)==' ') || ((_x)=='\t') || ((_x)=='\v') || \
+ ((_x)=='\f') || ((_x)=='\r') || ((_x)=='\n') )
+
+static int vfr_write_proc(struct file *file, const char *buffer,
+ u_long count, void *data)
+{
+ network_op_t op;
+ int ret, len;
+ int ts, te, tl; // token start, end, and length
+ int fs, fe, fl; // field.
+
+ len = count;
+ ts = te = 0;
+
+ memset(&op, 0, sizeof(network_op_t));
+
+ // get the command:
+ while ( count && isspace(buffer[ts]) ) { ts++; count--; } // skip spaces.
+ te = ts;
+ while ( count && !isspace(buffer[te]) ) { te++; count--; } // command end
+ if ( te <= ts ) goto bad;
+ tl = te - ts;
+
+ if ( strncmp(&buffer[ts], "ADD", tl) == 0 )
+ {
+ op.cmd = NETWORK_OP_ADDRULE;
+ }
+ else if ( strncmp(&buffer[ts], "DELETE", tl) == 0 )
+ {
+ op.cmd = NETWORK_OP_DELETERULE;
+ }
+ else if ( strncmp(&buffer[ts], "PRINT", tl) == 0 )
+ {
+ op.cmd = NETWORK_OP_GETRULELIST;
+ goto doneparsing;
+ }
+
+ ts = te;
+
+ // get the action
+ while ( count && (buffer[ts] == ' ') ) { ts++; count--; } // skip spaces.
+ te = ts;
+ while ( count && (buffer[te] != ' ') ) { te++; count--; } // command end
+ if ( te <= ts ) goto bad;
+ tl = te - ts;
+
+ if ( strncmp(&buffer[ts], "ACCEPT", tl) == 0 )
+ {
+ op.u.net_rule.action = NETWORK_ACTION_ACCEPT;
+ goto keyval;
+ }
+ if ( strncmp(&buffer[ts], "COUNT", tl) == 0 )
+ {
+ op.u.net_rule.action = NETWORK_ACTION_COUNT;
+ goto keyval;
+ }
+
+ // default case;
+ return (len);
+
+
+ // get the key=val pairs.
+ keyval:
+ while (count)
+ {
+ //get field
+ ts = te; while ( count && isspace(buffer[ts]) ) { ts++; count--; }
+ te = ts;
+ while ( count && !isspace(buffer[te]) && (buffer[te] != '=') )
+ { te++; count--; }
+ if ( te <= ts )
+ goto doneparsing;
+ tl = te - ts;
+ fs = ts; fe = te; fl = tl; // save the field markers.
+ // skip " = " (ignores extra equals.)
+ while ( count && (isspace(buffer[te]) || (buffer[te] == '=')) )
+ { te++; count--; }
+ ts = te;
+ while ( count && !isspace(buffer[te]) ) { te++; count--; }
+ tl = te - ts;
+
+ if ( (fl <= 0) || (tl <= 0) ) goto bad;
+
+ /* NB. Prefix matches must go first! */
+ if (strncmp(&buffer[fs], "src", fl) == 0)
+ {
+ op.u.net_rule.src_vif = VIF_ANY_INTERFACE;
+ }
+ else if (strncmp(&buffer[fs], "dst", fl) == 0)
+ {
+ op.u.net_rule.dst_vif = VIF_PHYSICAL_INTERFACE;
+ }
+ else if (strncmp(&buffer[fs], "srcaddr", fl) == 0)
+ {
+ op.u.net_rule.src_addr = getipaddr(&buffer[ts], tl);
+ }
+ else if (strncmp(&buffer[fs], "dstaddr", fl) == 0)
+ {
+ op.u.net_rule.dst_addr = getipaddr(&buffer[ts], tl);
+ }
+ else if (strncmp(&buffer[fs], "srcaddrmask", fl) == 0)
+ {
+ op.u.net_rule.src_addr_mask = getipaddr(&buffer[ts], tl);
+ }
+ else if (strncmp(&buffer[fs], "dstaddrmask", fl) == 0)
+ {
+ op.u.net_rule.dst_addr_mask = getipaddr(&buffer[ts], tl);
+ }
+ else if (strncmp(&buffer[fs], "srcport", fl) == 0)
+ {
+ op.u.net_rule.src_port = antous(&buffer[ts], tl);
+ }
+ else if (strncmp(&buffer[fs], "dstport", fl) == 0)
+ {
+ op.u.net_rule.dst_port = antous(&buffer[ts], tl);
+ }
+ else if (strncmp(&buffer[fs], "srcportmask", fl) == 0)
+ {
+ op.u.net_rule.src_port_mask = antous(&buffer[ts], tl);
+ }
+ else if (strncmp(&buffer[fs], "dstportmask", fl) == 0)
+ {
+ op.u.net_rule.dst_port_mask = antous(&buffer[ts], tl);
+ }
+ else if (strncmp(&buffer[fs], "srcdom", fl) == 0)
+ {
+ op.u.net_rule.src_vif |= anton(&buffer[ts], tl)<<VIF_DOMAIN_SHIFT;
+ }
+ else if (strncmp(&buffer[fs], "srcidx", fl) == 0)
+ {
+ op.u.net_rule.src_vif |= anton(&buffer[ts], tl);
+ }
+ else if (strncmp(&buffer[fs], "dstdom", fl) == 0)
+ {
+ op.u.net_rule.dst_vif |= anton(&buffer[ts], tl)<<VIF_DOMAIN_SHIFT;
+ }
+ else if (strncmp(&buffer[fs], "dstidx", fl) == 0)
+ {
+ op.u.net_rule.dst_vif |= anton(&buffer[ts], tl);
+ }
+ else if ( (strncmp(&buffer[fs], "proto", fl) == 0))
+ {
+ if (strncmp(&buffer[ts], "any", tl) == 0)
+ op.u.net_rule.proto = NETWORK_PROTO_ANY;
+ if (strncmp(&buffer[ts], "ip", tl) == 0)
+ op.u.net_rule.proto = NETWORK_PROTO_IP;
+ if (strncmp(&buffer[ts], "tcp", tl) == 0)
+ op.u.net_rule.proto = NETWORK_PROTO_TCP;
+ if (strncmp(&buffer[ts], "udp", tl) == 0)
+ op.u.net_rule.proto = NETWORK_PROTO_UDP;
+ if (strncmp(&buffer[ts], "arp", tl) == 0)
+ op.u.net_rule.proto = NETWORK_PROTO_ARP;
+ }
+ }
+
+ doneparsing:
+ ret = HYPERVISOR_network_op(&op);
+ return(len);
+
+ bad:
+ return(len);
+
+
+}
+
+static int __init init_module(void)
+{
+ *readbuf = '\0';
+ proc_vfr = create_proc_entry ("vfr", 0600, &proc_root);
+ if ( proc_vfr != NULL )
+ {
+ proc_vfr->owner = THIS_MODULE;
+ proc_vfr->nlink = 1;
+ proc_vfr->read_proc = vfr_read_proc;
+ proc_vfr->write_proc = vfr_write_proc;
+ printk("Successfully installed virtual firewall/router interface\n");
+ }
+ return 0;
+}
+
+static void __exit cleanup_module(void)
+{
+ if ( proc_vfr == NULL ) return;
+ remove_proc_entry("vfr", &proc_root);
+ proc_vfr = NULL;
+}
+
+module_init(init_module);
+module_exit(cleanup_module);
+
+/* Helper functions start here: */
+
+int anton(const char *buff, int len)
+{
+ int ret;
+ char c;
+ int sign = 1;
+
+ ret = 0;
+
+ if (len == 0) return 0;
+ if (*buff == '-') { sign = -1; buff++; len--; }
+
+ while ( (len) && ((c = *buff) >= '0') && (c <= '9') )
+ {
+ ret *= 10;
+ ret += c - '0';
+ buff++; len--;
+ }
+
+ ret *= sign;
+ return ret;
+}
+
+u16 antous(const char *buff, int len)
+{
+ u16 ret;
+ char c;
+
+ ret = 0;
+
+ while ( (len) && ((c = *buff) >= '0') && (c <= '9') )
+ {
+ ret *= 10;
+ ret += c - '0';
+ buff++; len--;
+ }
+
+ return ret;
+}
+
+u32 getipaddr(const char *buff, unsigned int len)
+{
+ char c;
+ u32 ret, val;
+
+ ret = 0; val = 0;
+
+ while ( len )
+ {
+ if (!((((c = *buff) >= '0') && ( c <= '9')) || ( c == '.' ) ) )
+ {
+ return(0); // malformed.
+ }
+
+ if ( c == '.' ) {
+ if (val > 255) return (0); //malformed.
+ ret = ret << 8;
+ ret += val;
+ val = 0;
+ len--; buff++;
+ continue;
+ }
+ val *= 10;
+ val += c - '0';
+ buff++; len--;
+ }
+ ret = ret << 8;
+ ret += val;
+
+ return (ret);
+}
+
--- /dev/null
+O_TARGET := net.o
+obj-y := network.o
+include $(TOPDIR)/Rules.make
--- /dev/null
+/******************************************************************************
+ * network.c
+ *
+ * Virtual network driver for XenoLinux.
+ *
+ * Copyright (c) 2002-2003, K A Fraser
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+
+#include <linux/netdevice.h>
+#include <linux/inetdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/init.h>
+
+#include <asm/io.h>
+#include <net/sock.h>
+#include <net/pkt_sched.h>
+
+#define NET_TX_IRQ _EVENT_NET_TX
+#define NET_RX_IRQ _EVENT_NET_RX
+
+#define TX_MAX_ENTRIES (TX_RING_SIZE - 2)
+#define RX_MAX_ENTRIES (RX_RING_SIZE - 2)
+
+#define TX_RING_INC(_i) (((_i)+1) & (TX_RING_SIZE-1))
+#define RX_RING_INC(_i) (((_i)+1) & (RX_RING_SIZE-1))
+#define TX_RING_ADD(_i,_j) (((_i)+(_j)) & (TX_RING_SIZE-1))
+#define RX_RING_ADD(_i,_j) (((_i)+(_j)) & (RX_RING_SIZE-1))
+
+#define RX_BUF_SIZE ((PAGE_SIZE/2)+1) /* Fool the slab allocator :-) */
+
+static void network_rx_int(int irq, void *dev_id, struct pt_regs *ptregs);
+static void network_tx_int(int irq, void *dev_id, struct pt_regs *ptregs);
+static void network_tx_buf_gc(struct net_device *dev);
+static void network_alloc_rx_buffers(struct net_device *dev);
+static void network_free_rx_buffers(struct net_device *dev);
+static void cleanup_module(void);
+
+static struct list_head dev_list;
+
+struct net_private
+{
+ struct list_head list;
+ struct net_device *dev;
+
+ struct net_device_stats stats;
+ atomic_t tx_entries;
+ unsigned int rx_resp_cons, tx_resp_cons, tx_full;
+ net_ring_t *net_ring;
+ net_idx_t *net_idx;
+ spinlock_t tx_lock;
+ unsigned int idx; /* Domain-specific index of this VIF. */
+
+ /*
+ * {tx,rx}_skbs store outstanding skbuffs. The first entry in each
+ * array is an index into a chain of free entries.
+ */
+ struct sk_buff *tx_skbs[TX_RING_SIZE];
+ struct sk_buff *rx_skbs[RX_RING_SIZE];
+};
+
+/* Access macros for acquiring freeing slots in {tx,rx}_skbs[]. */
+#define ADD_ID_TO_FREELIST(_list, _id) \
+ (_list)[(_id)] = (_list)[0]; \
+ (_list)[0] = (void *)(unsigned long)(_id);
+#define GET_ID_FROM_FREELIST(_list) \
+ ({ unsigned long _id = (unsigned long)(_list)[0]; \
+ (_list)[0] = (_list)[_id]; \
+ _id; })
+
+
+static void dbg_network_int(int irq, void *dev_id, struct pt_regs *ptregs)
+{
+ struct net_device *dev = (struct net_device *)dev_id;
+ struct net_private *np = dev->priv;
+ printk(KERN_ALERT "tx_full = %d, tx_entries = %d, tx_resp_cons = %d,"
+ " tx_req_prod = %d, tx_resp_prod = %d, tx_event = %d, state=%d\n",
+ np->tx_full, atomic_read(&np->tx_entries), np->tx_resp_cons,
+ np->net_idx->tx_req_prod, np->net_idx->tx_resp_prod,
+ np->net_idx->tx_event,
+ test_bit(__LINK_STATE_XOFF, &dev->state));
+ printk(KERN_ALERT "rx_resp_cons = %d,"
+ " rx_req_prod = %d, rx_resp_prod = %d, rx_event = %d\n",
+ np->rx_resp_cons, np->net_idx->rx_req_prod,
+ np->net_idx->rx_resp_prod, np->net_idx->rx_event);
+}
+
+
+static int network_open(struct net_device *dev)
+{
+ struct net_private *np = dev->priv;
+ int i, error = 0;
+
+ np->rx_resp_cons = np->tx_resp_cons = np->tx_full = 0;
+ memset(&np->stats, 0, sizeof(np->stats));
+ spin_lock_init(&np->tx_lock);
+ atomic_set(&np->tx_entries, 0);
+ memset(np->net_ring, 0, sizeof(*np->net_ring));
+ memset(np->net_idx, 0, sizeof(*np->net_idx));
+
+ /* Initialise {tx,rx}_skbs to be a free chain containing every entry. */
+ for ( i = 0; i < TX_RING_SIZE; i++ )
+ np->tx_skbs[i] = (void *)(i+1);
+ for ( i = 0; i < RX_RING_SIZE; i++ )
+ np->rx_skbs[i] = (void *)(i+1);
+
+ network_alloc_rx_buffers(dev);
+
+ error = request_irq(NET_RX_IRQ, network_rx_int,
+ SA_SAMPLE_RANDOM, "net-rx", dev);
+ if ( error )
+ {
+ printk(KERN_WARNING "%s: Could not allocate receive interrupt\n",
+ dev->name);
+ network_free_rx_buffers(dev);
+ goto fail;
+ }
+
+ error = request_irq(NET_TX_IRQ, network_tx_int,
+ SA_SAMPLE_RANDOM, "net-tx", dev);
+ if ( error )
+ {
+ printk(KERN_WARNING "%s: Could not allocate transmit interrupt\n",
+ dev->name);
+ free_irq(NET_RX_IRQ, dev);
+ network_free_rx_buffers(dev);
+ goto fail;
+ }
+
+ error = request_irq(_EVENT_DEBUG, dbg_network_int, SA_SHIRQ,
+ "debug", dev);
+ if ( error )
+ {
+ printk(KERN_WARNING "%s: Non-fatal error -- no debug interrupt\n",
+ dev->name);
+ }
+
+ printk("XenoLinux Virtual Network Driver installed as %s\n", dev->name);
+
+ netif_start_queue(dev);
+
+ MOD_INC_USE_COUNT;
+
+ return 0;
+
+ fail:
+ kfree(np);
+ return error;
+}
+
+
+static void network_tx_buf_gc(struct net_device *dev)
+{
+ unsigned int i;
+ struct net_private *np = dev->priv;
+ struct sk_buff *skb;
+ unsigned long flags;
+ unsigned int prod;
+ tx_entry_t *tx_ring = np->net_ring->tx_ring;
+
+ spin_lock_irqsave(&np->tx_lock, flags);
+
+ do {
+ prod = np->net_idx->tx_resp_prod;
+
+ for ( i = np->tx_resp_cons; i != prod; i = TX_RING_INC(i) )
+ {
+ skb = np->tx_skbs[tx_ring[i].resp.id];
+ ADD_ID_TO_FREELIST(np->tx_skbs, tx_ring[i].resp.id);
+ dev_kfree_skb_any(skb);
+ atomic_dec(&np->tx_entries);
+ }
+
+ np->tx_resp_cons = prod;
+
+ /* Set a new event, then check for race with update of tx_cons. */
+ np->net_idx->tx_event =
+ TX_RING_ADD(prod, (atomic_read(&np->tx_entries)>>1) + 1);
+ smp_mb();
+ }
+ while ( prod != np->net_idx->tx_resp_prod );
+
+ if ( np->tx_full && (atomic_read(&np->tx_entries) < TX_MAX_ENTRIES) )
+ {
+ np->tx_full = 0;
+ netif_wake_queue(dev);
+ }
+
+ spin_unlock_irqrestore(&np->tx_lock, flags);
+}
+
+inline pte_t *get_ppte(void *addr)
+{
+ pgd_t *pgd; pmd_t *pmd; pte_t *pte;
+ pgd = pgd_offset_k( (unsigned long)addr);
+ pmd = pmd_offset(pgd, (unsigned long)addr);
+ pte = pte_offset(pmd, (unsigned long)addr);
+ return pte;
+}
+
+static void network_alloc_rx_buffers(struct net_device *dev)
+{
+ unsigned int i, id;
+ struct net_private *np = dev->priv;
+ struct sk_buff *skb;
+ unsigned int end = RX_RING_ADD(np->rx_resp_cons, RX_MAX_ENTRIES);
+
+ for ( i = np->net_idx->rx_req_prod; i != end; i = RX_RING_INC(i) )
+ {
+ skb = dev_alloc_skb(RX_BUF_SIZE);
+ if ( skb == NULL ) break;
+ skb->dev = dev;
+
+ id = GET_ID_FROM_FREELIST(np->rx_skbs);
+ np->rx_skbs[id] = skb;
+
+ np->net_ring->rx_ring[i].req.id = (unsigned short)id;
+ np->net_ring->rx_ring[i].req.addr =
+ virt_to_machine(get_ppte(skb->head));
+ }
+
+ np->net_idx->rx_req_prod = i;
+
+ np->net_idx->rx_event = RX_RING_INC(np->rx_resp_cons);
+
+ /*
+ * We may have allocated buffers which have entries outstanding in
+ * the page update queue -- make sure we flush those first!
+ */
+ flush_page_update_queue();
+ HYPERVISOR_net_update();
+}
+
+
+static void network_free_rx_buffers(struct net_device *dev)
+{
+ unsigned int i;
+ struct net_private *np = dev->priv;
+ struct sk_buff *skb;
+
+ for ( i = np->rx_resp_cons;
+ i != np->net_idx->rx_req_prod;
+ i = RX_RING_INC(i) )
+ {
+ skb = np->rx_skbs[np->net_ring->rx_ring[i].req.id];
+ dev_kfree_skb_any(skb);
+ }
+}
+
+static int network_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+ unsigned int i, id;
+ struct net_private *np = (struct net_private *)dev->priv;
+
+ if ( np->tx_full )
+ {
+ printk(KERN_ALERT "%s: full queue wasn't stopped!\n", dev->name);
+ netif_stop_queue(dev);
+ return -ENOBUFS;
+ }
+ i = np->net_idx->tx_req_prod;
+
+ if ( (((unsigned long)skb->data & ~PAGE_MASK) + skb->len) >= PAGE_SIZE )
+ {
+ struct sk_buff *new_skb = dev_alloc_skb(RX_BUF_SIZE);
+ if ( new_skb == NULL ) return 1;
+ skb_put(new_skb, skb->len);
+ memcpy(new_skb->data, skb->data, skb->len);
+ dev_kfree_skb(skb);
+ skb = new_skb;
+ }
+
+ id = GET_ID_FROM_FREELIST(np->tx_skbs);
+ np->tx_skbs[id] = skb;
+
+ np->net_ring->tx_ring[i].req.id = (unsigned short)id;
+ np->net_ring->tx_ring[i].req.addr =
+ phys_to_machine(virt_to_phys(skb->data));
+ np->net_ring->tx_ring[i].req.size = skb->len;
+ np->net_idx->tx_req_prod = TX_RING_INC(i);
+ atomic_inc(&np->tx_entries);
+
+ np->stats.tx_bytes += skb->len;
+ np->stats.tx_packets++;
+
+ spin_lock_irq(&np->tx_lock);
+ if ( atomic_read(&np->tx_entries) >= TX_MAX_ENTRIES )
+ {
+ np->tx_full = 1;
+ netif_stop_queue(dev);
+ }
+ spin_unlock_irq(&np->tx_lock);
+
+ network_tx_buf_gc(dev);
+
+ HYPERVISOR_net_update();
+
+ return 0;
+}
+
+
+static void network_rx_int(int irq, void *dev_id, struct pt_regs *ptregs)
+{
+ unsigned int i;
+ struct net_device *dev = (struct net_device *)dev_id;
+ struct net_private *np = dev->priv;
+ struct sk_buff *skb;
+ rx_resp_entry_t *rx;
+
+ again:
+ for ( i = np->rx_resp_cons;
+ i != np->net_idx->rx_resp_prod;
+ i = RX_RING_INC(i) )
+ {
+ rx = &np->net_ring->rx_ring[i].resp;
+
+ skb = np->rx_skbs[rx->id];
+ ADD_ID_TO_FREELIST(np->rx_skbs, rx->id);
+
+ if ( rx->status != RING_STATUS_OK )
+ {
+ printk(KERN_ALERT "bad buffer on RX ring!(%d)\n", rx->status);
+ dev_kfree_skb_any(skb);
+ continue;
+ }
+
+ /*
+ * Set up shinfo -- from alloc_skb This was particularily nasty: the
+ * shared info is hidden at the back of the data area (presumably so it
+ * can be shared), but on page flip it gets very spunked.
+ */
+ atomic_set(&(skb_shinfo(skb)->dataref), 1);
+ skb_shinfo(skb)->nr_frags = 0;
+ skb_shinfo(skb)->frag_list = NULL;
+
+ phys_to_machine_mapping[virt_to_phys(skb->head) >> PAGE_SHIFT] =
+ (*(unsigned long *)get_ppte(skb->head)) >> PAGE_SHIFT;
+
+ if ( rx->offset < 16 )
+ {
+ printk(KERN_ALERT "need pkt offset >= 16 (got %d)\n", rx->offset);
+ dev_kfree_skb_any(skb);
+ continue;
+ }
+
+ skb_reserve(skb, rx->offset - 16);
+
+ skb_put(skb, rx->size);
+ skb->protocol = eth_type_trans(skb, dev);
+
+ np->stats.rx_packets++;
+
+ np->stats.rx_bytes += rx->size;
+ netif_rx(skb);
+ dev->last_rx = jiffies;
+ }
+
+ np->rx_resp_cons = i;
+
+ network_alloc_rx_buffers(dev);
+
+ /* Deal with hypervisor racing our resetting of rx_event. */
+ smp_mb();
+ if ( np->net_idx->rx_resp_prod != i ) goto again;
+}
+
+
+static void network_tx_int(int irq, void *dev_id, struct pt_regs *ptregs)
+{
+ struct net_device *dev = (struct net_device *)dev_id;
+ network_tx_buf_gc(dev);
+}
+
+
+int network_close(struct net_device *dev)
+{
+ netif_stop_queue(dev);
+
+ free_irq(NET_RX_IRQ, dev);
+ free_irq(NET_TX_IRQ, dev);
+
+ /*
+ * XXXX This cannot be done safely until be have a proper interface
+ * for setting up and tearing down virtual interfaces on the fly.
+ * Currently the receive buffers are locked down by Xen and we have
+ * no sensible way of retrieving them.
+ */
+#if 0
+ network_free_rx_buffers(dev);
+ kfree(np->net_ring->rx_ring);
+ kfree(np->net_ring->tx_ring);
+#endif
+
+ MOD_DEC_USE_COUNT;
+
+ return 0;
+}
+
+
+static struct net_device_stats *network_get_stats(struct net_device *dev)
+{
+ struct net_private *np = (struct net_private *)dev->priv;
+ return &np->stats;
+}
+
+
+/*
+ * This notifier is installed for domain 0 only.
+ * All other domains have VFR rules installed on their behalf by domain 0
+ * when they are created. For bootstrap, Xen creates wildcard rules for
+ * domain 0 -- this notifier is used to detect when we find our proper
+ * IP address, so we can poke down proper rules and remove the wildcards.
+ */
+static int inetdev_notify(struct notifier_block *this,
+ unsigned long event,
+ void *ptr)
+{
+ struct in_ifaddr *ifa = (struct in_ifaddr *)ptr;
+ struct net_device *dev = ifa->ifa_dev->dev;
+ struct list_head *ent;
+ struct net_private *np;
+ int idx = -1;
+ network_op_t op;
+ static int removed_bootstrap_rules = 0;
+
+ list_for_each ( ent, &dev_list )
+ {
+ np = list_entry(dev_list.next, struct net_private, list);
+ if ( np->dev == dev )
+ idx = np->idx;
+ }
+
+ if ( idx == -1 )
+ goto out;
+
+ memset(&op, 0, sizeof(op));
+ op.u.net_rule.proto = NETWORK_PROTO_ANY;
+ op.u.net_rule.action = NETWORK_ACTION_ACCEPT;
+
+ if ( event == NETDEV_UP )
+ op.cmd = NETWORK_OP_ADDRULE;
+ else if ( event == NETDEV_DOWN )
+ op.cmd = NETWORK_OP_DELETERULE;
+ else
+ goto out;
+
+ op.u.net_rule.src_vif = idx;
+ op.u.net_rule.dst_vif = VIF_PHYSICAL_INTERFACE;
+ op.u.net_rule.src_addr = ntohl(ifa->ifa_address);
+ op.u.net_rule.src_addr_mask = ~0UL;
+ op.u.net_rule.dst_addr = 0;
+ op.u.net_rule.dst_addr_mask = 0;
+ (void)HYPERVISOR_network_op(&op);
+
+ op.u.net_rule.src_vif = VIF_ANY_INTERFACE;
+ op.u.net_rule.dst_vif = idx;
+ op.u.net_rule.src_addr = 0;
+ op.u.net_rule.src_addr_mask = 0;
+ op.u.net_rule.dst_addr = ntohl(ifa->ifa_address);
+ op.u.net_rule.dst_addr_mask = ~0UL;
+ (void)HYPERVISOR_network_op(&op);
+
+ /*
+ * When the first real interface is brought up we delete the start-of-day
+ * bootstrap rules -- they were only installed to allow an initial DHCP
+ * request and response.
+ */
+ if ( (idx == 0) && (event == NETDEV_UP) && !removed_bootstrap_rules )
+ {
+ memset(&op, 0, sizeof(op));
+ op.cmd = NETWORK_OP_DELETERULE;
+ op.u.net_rule.proto = NETWORK_PROTO_ANY;
+ op.u.net_rule.action = NETWORK_ACTION_ACCEPT;
+ op.u.net_rule.src_vif = 0;
+ op.u.net_rule.dst_vif = VIF_PHYSICAL_INTERFACE;
+ (void)HYPERVISOR_network_op(&op);
+ op.u.net_rule.src_vif = VIF_ANY_INTERFACE;
+ op.u.net_rule.dst_vif = 0;
+ (void)HYPERVISOR_network_op(&op);
+
+ removed_bootstrap_rules = 1;
+ }
+
+ out:
+ return NOTIFY_DONE;
+}
+
+static struct notifier_block notifier_inetdev = {
+ .notifier_call = inetdev_notify,
+ .next = NULL,
+ .priority = 0
+};
+
+
+int __init init_module(void)
+{
+ int i, fixmap_idx=-1, err;
+ struct net_device *dev;
+ struct net_private *np;
+
+ INIT_LIST_HEAD(&dev_list);
+
+ if ( start_info.dom_id == 0 )
+ {
+ /*
+ * Domain 0 creates wildcard rules to allow DHCP to find its first IP
+ * address. These wildcard rules are deleted when the first inet
+ * interface is brought up.
+ */
+ network_op_t op;
+ memset(&op, 0, sizeof(op));
+ op.cmd = NETWORK_OP_ADDRULE;
+ op.u.net_rule.proto = NETWORK_PROTO_ANY;
+ op.u.net_rule.action = NETWORK_ACTION_ACCEPT;
+ op.u.net_rule.src_vif = 0;
+ op.u.net_rule.dst_vif = VIF_PHYSICAL_INTERFACE;
+ (void)HYPERVISOR_network_op(&op);
+ op.u.net_rule.src_vif = VIF_ANY_INTERFACE;
+ op.u.net_rule.dst_vif = 0;
+ (void)HYPERVISOR_network_op(&op);
+
+ /*
+ * Domain 0 must poke its own network rules as it discovers its IP
+ * addresses. All other domains have a privileged "parent" to do this
+ * for them at start of day.
+ */
+ (void)register_inetaddr_notifier(¬ifier_inetdev);
+ }
+
+ for ( i = 0; i < MAX_DOMAIN_VIFS; i++ )
+ {
+ if ( start_info.net_rings[i] == 0 )
+ continue;
+
+ /* We actually only support up to 4 vifs right now. */
+ if ( ++fixmap_idx == 4 )
+ break;
+
+ dev = alloc_etherdev(sizeof(struct net_private));
+ if ( dev == NULL )
+ {
+ err = -ENOMEM;
+ goto fail;
+ }
+
+ set_fixmap(FIX_NETRING0_BASE+fixmap_idx, start_info.net_rings[i]);
+
+ np = dev->priv;
+ np->net_ring = (net_ring_t *)fix_to_virt(FIX_NETRING0_BASE+fixmap_idx);
+ np->net_idx = &HYPERVISOR_shared_info->net_idx[i];
+ np->idx = i;
+
+ SET_MODULE_OWNER(dev);
+ dev->open = network_open;
+ dev->hard_start_xmit = network_start_xmit;
+ dev->stop = network_close;
+ dev->get_stats = network_get_stats;
+
+ memcpy(dev->dev_addr, start_info.net_vmac[i], ETH_ALEN);
+
+ if ( (err = register_netdev(dev)) != 0 )
+ {
+ kfree(dev);
+ goto fail;
+ }
+
+ np->dev = dev;
+ list_add(&np->list, &dev_list);
+ }
+
+ return 0;
+
+ fail:
+ cleanup_module();
+ return err;
+}
+
+
+static void cleanup_module(void)
+{
+ struct net_private *np;
+ struct net_device *dev;
+
+ while ( !list_empty(&dev_list) )
+ {
+ np = list_entry(dev_list.next, struct net_private, list);
+ list_del(&np->list);
+ dev = np->dev;
+ unregister_netdev(dev);
+ kfree(dev);
+ }
+
+ if ( start_info.dom_id == 0 )
+ (void)unregister_inetaddr_notifier(¬ifier_inetdev);
+}
+
+
+module_init(init_module);
+module_exit(cleanup_module);
--- /dev/null
+
+.S.o:
+ $(CC) $(AFLAGS) -traditional -c $< -o $*.o
+
+all: kernel.o head.o init_task.o
+
+O_TARGET := kernel.o
+
+export-objs := i386_ksyms.o
+
+obj-y := process.o semaphore.o signal.o entry.o traps.o irq.o \
+ ptrace.o ioport.o ldt.o setup.o time.o sys_i386.o \
+ i386_ksyms.o i387.o hypervisor.o
+
+include $(TOPDIR)/Rules.make
--- /dev/null
+/*
+ * linux/arch/i386/entry.S
+ *
+ * Copyright (C) 1991, 1992 Linus Torvalds
+ */
+
+/*
+ * entry.S contains the system-call and fault low-level handling routines.
+ * This also contains the timer-interrupt handler, as well as all interrupts
+ * and faults that can result in a task-switch.
+ *
+ * NOTE: This code handles signal-recognition, which happens every time
+ * after a timer-interrupt and after each system call.
+ *
+ * I changed all the .align's to 4 (16 byte alignment), as that's faster
+ * on a 486.
+ *
+ * Stack layout in 'ret_from_system_call':
+ * ptrace needs to have all regs on the stack.
+ * if the order here is changed, it needs to be
+ * updated in fork.c:copy_process, signal.c:do_signal,
+ * ptrace.c and ptrace.h
+ *
+ * 0(%esp) - %ebx
+ * 4(%esp) - %ecx
+ * 8(%esp) - %edx
+ * C(%esp) - %esi
+ * 10(%esp) - %edi
+ * 14(%esp) - %ebp
+ * 18(%esp) - %eax
+ * 1C(%esp) - %ds
+ * 20(%esp) - %es
+ * 24(%esp) - orig_eax
+ * 28(%esp) - %eip
+ * 2C(%esp) - %cs
+ * 30(%esp) - %eflags
+ * 34(%esp) - %oldesp
+ * 38(%esp) - %oldss
+ *
+ * "current" is in register %ebx during any slow entries.
+ */
+
+#include <linux/config.h>
+#include <linux/sys.h>
+#include <linux/linkage.h>
+#include <asm/segment.h>
+#include <asm/smp.h>
+
+EBX = 0x00
+ECX = 0x04
+EDX = 0x08
+ESI = 0x0C
+EDI = 0x10
+EBP = 0x14
+EAX = 0x18
+DS = 0x1C
+ES = 0x20
+ORIG_EAX = 0x24
+EIP = 0x28
+CS = 0x2C
+EFLAGS = 0x30
+OLDESP = 0x34
+OLDSS = 0x38
+
+CF_MASK = 0x00000001
+TF_MASK = 0x00000100
+IF_MASK = 0x00000200
+DF_MASK = 0x00000400
+NT_MASK = 0x00004000
+
+/*
+ * these are offsets into the task-struct.
+ */
+state = 0
+flags = 4
+sigpending = 8
+addr_limit = 12
+exec_domain = 16
+need_resched = 20
+tsk_ptrace = 24
+processor = 52
+
+ENOSYS = 38
+
+
+#define SAVE_ALL \
+ cld; \
+ pushl %es; \
+ pushl %ds; \
+ pushl %eax; \
+ pushl %ebp; \
+ pushl %edi; \
+ pushl %esi; \
+ pushl %edx; \
+ pushl %ecx; \
+ pushl %ebx; \
+ movl $(__KERNEL_DS),%edx; \
+ movl %edx,%ds; \
+ movl %edx,%es;
+
+#define RESTORE_ALL \
+ popl %ebx; \
+ popl %ecx; \
+ popl %edx; \
+ popl %esi; \
+ popl %edi; \
+ popl %ebp; \
+ popl %eax; \
+1: popl %ds; \
+2: popl %es; \
+ addl $4,%esp; \
+3: iret; \
+.section .fixup,"ax"; \
+4: movl $0,(%esp); \
+ jmp 1b; \
+5: movl $0,(%esp); \
+ jmp 2b; \
+6: pushl %ss; \
+ popl %ds; \
+ pushl %ss; \
+ popl %es; \
+ pushl $11; \
+ call do_exit; \
+.previous; \
+.section __ex_table,"a";\
+ .align 4; \
+ .long 1b,4b; \
+ .long 2b,5b; \
+ .long 3b,6b; \
+.previous
+
+#define GET_CURRENT(reg) \
+ movl $-8192, reg; \
+ andl %esp, reg
+
+ENTRY(lcall7)
+ pushfl # We get a different stack layout with call
+ pushl %eax # gates, which has to be cleaned up later..
+ SAVE_ALL
+ movl EIP(%esp),%eax # due to call gates, this is eflags, not eip..
+ movl CS(%esp),%edx # this is eip..
+ movl EFLAGS(%esp),%ecx # and this is cs..
+ movl %eax,EFLAGS(%esp) #
+ andl $~(NT_MASK|TF_MASK|DF_MASK), %eax
+ pushl %eax
+ popfl
+ movl %edx,EIP(%esp) # Now we move them to their "normal" places
+ movl %ecx,CS(%esp) #
+ movl %esp,%ebx
+ pushl %ebx
+ andl $-8192,%ebx # GET_CURRENT
+ movl exec_domain(%ebx),%edx # Get the execution domain
+ movl 4(%edx),%edx # Get the lcall7 handler for the domain
+ pushl $0x7
+ call *%edx
+ addl $4, %esp
+ popl %eax
+ jmp ret_from_sys_call
+
+ENTRY(lcall27)
+ pushfl # We get a different stack layout with call
+ pushl %eax # gates, which has to be cleaned up later..
+ SAVE_ALL
+ movl EIP(%esp),%eax # due to call gates, this is eflags, not eip..
+ movl CS(%esp),%edx # this is eip..
+ movl EFLAGS(%esp),%ecx # and this is cs..
+ movl %eax,EFLAGS(%esp) #
+ andl $~(NT_MASK|TF_MASK|DF_MASK), %eax
+ pushl %eax
+ popfl
+ movl %edx,EIP(%esp) # Now we move them to their "normal" places
+ movl %ecx,CS(%esp) #
+ movl %esp,%ebx
+ pushl %ebx
+ andl $-8192,%ebx # GET_CURRENT
+ movl exec_domain(%ebx),%edx # Get the execution domain
+ movl 4(%edx),%edx # Get the lcall7 handler for the domain
+ pushl $0x27
+ call *%edx
+ addl $4, %esp
+ popl %eax
+ jmp ret_from_sys_call
+
+
+ENTRY(ret_from_fork)
+ pushl %ebx
+ call SYMBOL_NAME(schedule_tail)
+ addl $4, %esp
+ GET_CURRENT(%ebx)
+ testb $0x02,tsk_ptrace(%ebx) # PT_TRACESYS
+ jne tracesys_exit
+ jmp ret_from_sys_call
+
+/*
+ * Return to user mode is not as complex as all this looks,
+ * but we want the default path for a system call return to
+ * go as quickly as possible which is why some of this is
+ * less clear than it otherwise should be.
+ */
+
+ENTRY(system_call)
+ pushl %eax # save orig_eax
+ SAVE_ALL
+ GET_CURRENT(%ebx)
+ testb $0x02,tsk_ptrace(%ebx) # PT_TRACESYS
+ jne tracesys
+ cmpl $(NR_syscalls),%eax
+ jae badsys
+ call *SYMBOL_NAME(sys_call_table)(,%eax,4)
+ movl %eax,EAX(%esp) # save the return value
+ENTRY(ret_from_sys_call)
+ movl SYMBOL_NAME(HYPERVISOR_shared_info),%esi
+ btrl $EVENTS_MASTER_ENABLE_BIT,4(%esi) # make tests atomic
+ret_syscall_tests:
+ cmpl $0,need_resched(%ebx)
+ jne reschedule
+ cmpl $0,sigpending(%ebx)
+ je safesti # ensure need_resched updates are seen
+signal_return:
+ btsl $EVENTS_MASTER_ENABLE_BIT,4(%esi) # reenable event callbacks
+ movl %esp,%eax
+ xorl %edx,%edx
+ call SYMBOL_NAME(do_signal)
+ jmp ret_from_sys_call
+
+ ALIGN
+restore_all:
+ RESTORE_ALL
+
+ ALIGN
+tracesys:
+ movl $-ENOSYS,EAX(%esp)
+ call SYMBOL_NAME(syscall_trace)
+ movl ORIG_EAX(%esp),%eax
+ cmpl $(NR_syscalls),%eax
+ jae tracesys_exit
+ call *SYMBOL_NAME(sys_call_table)(,%eax,4)
+ movl %eax,EAX(%esp) # save the return value
+tracesys_exit:
+ call SYMBOL_NAME(syscall_trace)
+ jmp ret_from_sys_call
+badsys:
+ movl $-ENOSYS,EAX(%esp)
+ jmp ret_from_sys_call
+
+ ALIGN
+ENTRY(ret_from_intr)
+ GET_CURRENT(%ebx)
+ret_from_exception:
+ movb CS(%esp),%al
+ testl $2,%eax
+ jne ret_from_sys_call
+ jmp restore_all
+
+ ALIGN
+reschedule:
+ btsl $EVENTS_MASTER_ENABLE_BIT,4(%esi) # reenable event callbacks
+ call SYMBOL_NAME(schedule) # test
+ jmp ret_from_sys_call
+
+ENTRY(divide_error)
+ pushl $0 # no error code
+ pushl $ SYMBOL_NAME(do_divide_error)
+ ALIGN
+error_code:
+ pushl %ds
+ pushl %eax
+ xorl %eax,%eax
+ pushl %ebp
+ pushl %edi
+ pushl %esi
+ pushl %edx
+ decl %eax # eax = -1
+ pushl %ecx
+ pushl %ebx
+ GET_CURRENT(%ebx)
+ cld
+ movl %es,%ecx
+ movl ORIG_EAX(%esp), %esi # get the error code
+ movl ES(%esp), %edi # get the function address
+ movl %eax, ORIG_EAX(%esp)
+ movl %ecx, ES(%esp)
+ movl %esp,%edx
+ pushl %esi # push the error code
+ pushl %edx # push the pt_regs pointer
+ movl $(__KERNEL_DS),%edx
+ movl %edx,%ds
+ movl %edx,%es
+ call *%edi
+ addl $8,%esp
+ jmp ret_from_exception
+
+# A note on the "critical region" in our callback handler.
+# We want to avoid stacking callback handlers due to events occurring
+# during handling of the last event. To do this, we keep events disabled
+# until we've done all processing. HOWEVER, we must enable events before
+# popping the stack frame (can't be done atomically) and so it would still
+# be possible to get enough handler activations to overflow the stack.
+# Although unlikely, bugs of that kind are hard to track down, so we'd
+# like to avoid the possibility.
+# So, on entry to the handler we detect whether we interrupted an
+# existing activation in its critical region -- if so, we pop the current
+# activation and restart the handler using the previous one.
+ENTRY(hypervisor_callback)
+ pushl %eax
+ SAVE_ALL
+ GET_CURRENT(%ebx)
+ movl EIP(%esp),%eax
+ cmpl $scrit,%eax
+ jb 11f
+ cmpl $ecrit,%eax
+ jb critical_region_fixup
+11: push %esp
+ call do_hypervisor_callback
+ add $4,%esp
+ movl SYMBOL_NAME(HYPERVISOR_shared_info),%esi
+ xorl %eax,%eax
+ movb CS(%esp),%cl
+ test $2,%cl # slow return to ring 2 or 3
+ jne ret_syscall_tests
+safesti:btsl $EVENTS_MASTER_ENABLE_BIT,4(%esi) # reenable event callbacks
+scrit: /**** START OF CRITICAL REGION ****/
+ cmpl %eax,(%esi)
+ jne 14f # process more events if necessary...
+ RESTORE_ALL
+14: btrl $EVENTS_MASTER_ENABLE_BIT,4(%esi)
+ jmp 11b
+ecrit: /**** END OF CRITICAL REGION ****/
+# [How we do the fixup]. We want to merge the current stack frame with the
+# just-interrupted frame. How we do this depends on where in the critical
+# region the interrupted handler was executing, and so how many saved
+# registers are in each frame. We do this quickly using the lookup table
+# 'critical_fixup_table'. For each byte offset in the critical region, it
+# provides the number of bytes which have already been popped from the
+# interrupted stack frame.
+critical_region_fixup:
+ addl $critical_fixup_table-scrit,%eax
+ movzbl (%eax),%eax # %eax contains num bytes popped
+ mov %esp,%esi
+ add %eax,%esi # %esi points at end of src region
+ mov %esp,%edi
+ add $0x34,%edi # %edi points at end of dst region
+ mov %eax,%ecx
+ shr $2,%ecx # convert words to bytes
+ je 16f # skip loop if nothing to copy
+15: subl $4,%esi # pre-decrementing copy loop
+ subl $4,%edi
+ movl (%esi),%eax
+ movl %eax,(%edi)
+ loop 15b
+16: movl %edi,%esp # final %edi is top of merged stack
+ jmp 11b
+
+critical_fixup_table:
+ .byte 0x00,0x00 # cmpl %eax,(%esi)
+ .byte 0x00,0x00 # jne 14f
+ .byte 0x00 # pop %ebx
+ .byte 0x04 # pop %ecx
+ .byte 0x08 # pop %edx
+ .byte 0x0c # pop %esi
+ .byte 0x10 # pop %edi
+ .byte 0x14 # pop %ebp
+ .byte 0x18 # pop %eax
+ .byte 0x1c # pop %ds
+ .byte 0x20 # pop %es
+ .byte 0x24,0x24,0x24 # add $4,%esp
+ .byte 0x28 # iret
+ .byte 0x00,0x00,0x00,0x00,0x00 # btrl $31,4(%esi)
+ .byte 0x00,0x00 # jmp 11b
+
+# Hypervisor uses this for application faults while it executes.
+ENTRY(failsafe_callback)
+1: pop %ds
+2: pop %es
+3: pop %fs
+4: pop %gs
+5: iret
+.section .fixup,"ax"; \
+6: movl $0,(%esp); \
+ jmp 1b; \
+7: movl $0,(%esp); \
+ jmp 2b; \
+8: movl $0,(%esp); \
+ jmp 3b; \
+9: movl $0,(%esp); \
+ jmp 4b; \
+10: pushl %ss; \
+ popl %ds; \
+ pushl %ss; \
+ popl %es; \
+ pushl $11; \
+ call do_exit; \
+.previous; \
+.section __ex_table,"a";\
+ .align 4; \
+ .long 1b,6b; \
+ .long 2b,7b; \
+ .long 3b,8b; \
+ .long 4b,9b; \
+ .long 5b,10b; \
+.previous
+
+ENTRY(coprocessor_error)
+ pushl $0
+ pushl $ SYMBOL_NAME(do_coprocessor_error)
+ jmp error_code
+
+ENTRY(simd_coprocessor_error)
+ pushl $0
+ pushl $ SYMBOL_NAME(do_simd_coprocessor_error)
+ jmp error_code
+
+ENTRY(device_not_available)
+ pushl $-1 # mark this as an int
+ SAVE_ALL
+ GET_CURRENT(%ebx)
+ call SYMBOL_NAME(math_state_restore)
+ jmp ret_from_exception
+
+ENTRY(debug)
+ pushl $0
+ pushl $ SYMBOL_NAME(do_debug)
+ jmp error_code
+
+ENTRY(int3)
+ pushl $0
+ pushl $ SYMBOL_NAME(do_int3)
+ jmp error_code
+
+ENTRY(overflow)
+ pushl $0
+ pushl $ SYMBOL_NAME(do_overflow)
+ jmp error_code
+
+ENTRY(bounds)
+ pushl $0
+ pushl $ SYMBOL_NAME(do_bounds)
+ jmp error_code
+
+ENTRY(invalid_op)
+ pushl $0
+ pushl $ SYMBOL_NAME(do_invalid_op)
+ jmp error_code
+
+ENTRY(coprocessor_segment_overrun)
+ pushl $0
+ pushl $ SYMBOL_NAME(do_coprocessor_segment_overrun)
+ jmp error_code
+
+ENTRY(double_fault)
+ pushl $ SYMBOL_NAME(do_double_fault)
+ jmp error_code
+
+ENTRY(invalid_TSS)
+ pushl $ SYMBOL_NAME(do_invalid_TSS)
+ jmp error_code
+
+ENTRY(segment_not_present)
+ pushl $ SYMBOL_NAME(do_segment_not_present)
+ jmp error_code
+
+ENTRY(stack_segment)
+ pushl $ SYMBOL_NAME(do_stack_segment)
+ jmp error_code
+
+ENTRY(general_protection)
+ pushl $ SYMBOL_NAME(do_general_protection)
+ jmp error_code
+
+ENTRY(alignment_check)
+ pushl $ SYMBOL_NAME(do_alignment_check)
+ jmp error_code
+
+# This handler is special, because it gets an extra value on its stack,
+# which is the linear faulting address.
+ENTRY(page_fault)
+ pushl %ds
+ pushl %eax
+ xorl %eax,%eax
+ pushl %ebp
+ pushl %edi
+ pushl %esi
+ pushl %edx
+ decl %eax # eax = -1
+ pushl %ecx
+ pushl %ebx
+ GET_CURRENT(%ebx)
+ cld
+ movl %es,%ecx
+ movl ORIG_EAX(%esp), %esi # get the error code
+ movl ES(%esp), %edi # get the faulting address
+ movl %eax, ORIG_EAX(%esp)
+ movl %ecx, ES(%esp)
+ movl %esp,%edx
+ pushl %edi # push the faulting address
+ pushl %esi # push the error code
+ pushl %edx # push the pt_regs pointer
+ movl $(__KERNEL_DS),%edx
+ movl %edx,%ds
+ movl %edx,%es
+ call SYMBOL_NAME(do_page_fault)
+ addl $12,%esp
+ jmp ret_from_exception
+
+ENTRY(machine_check)
+ pushl $0
+ pushl $ SYMBOL_NAME(do_machine_check)
+ jmp error_code
+
+ENTRY(spurious_interrupt_bug)
+ pushl $0
+ pushl $ SYMBOL_NAME(do_spurious_interrupt_bug)
+ jmp error_code
+
+.data
+ENTRY(sys_call_table)
+ .long SYMBOL_NAME(sys_ni_syscall) /* 0 - old "setup()" system call*/
+ .long SYMBOL_NAME(sys_exit)
+ .long SYMBOL_NAME(sys_fork)
+ .long SYMBOL_NAME(sys_read)
+ .long SYMBOL_NAME(sys_write)
+ .long SYMBOL_NAME(sys_open) /* 5 */
+ .long SYMBOL_NAME(sys_close)
+ .long SYMBOL_NAME(sys_waitpid)
+ .long SYMBOL_NAME(sys_creat)
+ .long SYMBOL_NAME(sys_link)
+ .long SYMBOL_NAME(sys_unlink) /* 10 */
+ .long SYMBOL_NAME(sys_execve)
+ .long SYMBOL_NAME(sys_chdir)
+ .long SYMBOL_NAME(sys_time)
+ .long SYMBOL_NAME(sys_mknod)
+ .long SYMBOL_NAME(sys_chmod) /* 15 */
+ .long SYMBOL_NAME(sys_lchown16)
+ .long SYMBOL_NAME(sys_ni_syscall) /* old break syscall holder */
+ .long SYMBOL_NAME(sys_stat)
+ .long SYMBOL_NAME(sys_lseek)
+ .long SYMBOL_NAME(sys_getpid) /* 20 */
+ .long SYMBOL_NAME(sys_mount)
+ .long SYMBOL_NAME(sys_oldumount)
+ .long SYMBOL_NAME(sys_setuid16)
+ .long SYMBOL_NAME(sys_getuid16)
+ .long SYMBOL_NAME(sys_stime) /* 25 */
+ .long SYMBOL_NAME(sys_ptrace)
+ .long SYMBOL_NAME(sys_alarm)
+ .long SYMBOL_NAME(sys_fstat)
+ .long SYMBOL_NAME(sys_pause)
+ .long SYMBOL_NAME(sys_utime) /* 30 */
+ .long SYMBOL_NAME(sys_ni_syscall) /* old stty syscall holder */
+ .long SYMBOL_NAME(sys_ni_syscall) /* old gtty syscall holder */
+ .long SYMBOL_NAME(sys_access)
+ .long SYMBOL_NAME(sys_nice)
+ .long SYMBOL_NAME(sys_ni_syscall) /* 35 */ /* old ftime syscall holder */
+ .long SYMBOL_NAME(sys_sync)
+ .long SYMBOL_NAME(sys_kill)
+ .long SYMBOL_NAME(sys_rename)
+ .long SYMBOL_NAME(sys_mkdir)
+ .long SYMBOL_NAME(sys_rmdir) /* 40 */
+ .long SYMBOL_NAME(sys_dup)
+ .long SYMBOL_NAME(sys_pipe)
+ .long SYMBOL_NAME(sys_times)
+ .long SYMBOL_NAME(sys_ni_syscall) /* old prof syscall holder */
+ .long SYMBOL_NAME(sys_brk) /* 45 */
+ .long SYMBOL_NAME(sys_setgid16)
+ .long SYMBOL_NAME(sys_getgid16)
+ .long SYMBOL_NAME(sys_signal)
+ .long SYMBOL_NAME(sys_geteuid16)
+ .long SYMBOL_NAME(sys_getegid16) /* 50 */
+ .long SYMBOL_NAME(sys_acct)
+ .long SYMBOL_NAME(sys_umount) /* recycled never used phys() */
+ .long SYMBOL_NAME(sys_ni_syscall) /* old lock syscall holder */
+ .long SYMBOL_NAME(sys_ioctl)
+ .long SYMBOL_NAME(sys_fcntl) /* 55 */
+ .long SYMBOL_NAME(sys_ni_syscall) /* old mpx syscall holder */
+ .long SYMBOL_NAME(sys_setpgid)
+ .long SYMBOL_NAME(sys_ni_syscall) /* old ulimit syscall holder */
+ .long SYMBOL_NAME(sys_olduname)
+ .long SYMBOL_NAME(sys_umask) /* 60 */
+ .long SYMBOL_NAME(sys_chroot)
+ .long SYMBOL_NAME(sys_ustat)
+ .long SYMBOL_NAME(sys_dup2)
+ .long SYMBOL_NAME(sys_getppid)
+ .long SYMBOL_NAME(sys_getpgrp) /* 65 */
+ .long SYMBOL_NAME(sys_setsid)
+ .long SYMBOL_NAME(sys_sigaction)
+ .long SYMBOL_NAME(sys_sgetmask)
+ .long SYMBOL_NAME(sys_ssetmask)
+ .long SYMBOL_NAME(sys_setreuid16) /* 70 */
+ .long SYMBOL_NAME(sys_setregid16)
+ .long SYMBOL_NAME(sys_sigsuspend)
+ .long SYMBOL_NAME(sys_sigpending)
+ .long SYMBOL_NAME(sys_sethostname)
+ .long SYMBOL_NAME(sys_setrlimit) /* 75 */
+ .long SYMBOL_NAME(sys_old_getrlimit)
+ .long SYMBOL_NAME(sys_getrusage)
+ .long SYMBOL_NAME(sys_gettimeofday)
+ .long SYMBOL_NAME(sys_settimeofday)
+ .long SYMBOL_NAME(sys_getgroups16) /* 80 */
+ .long SYMBOL_NAME(sys_setgroups16)
+ .long SYMBOL_NAME(old_select)
+ .long SYMBOL_NAME(sys_symlink)
+ .long SYMBOL_NAME(sys_lstat)
+ .long SYMBOL_NAME(sys_readlink) /* 85 */
+ .long SYMBOL_NAME(sys_uselib)
+ .long SYMBOL_NAME(sys_swapon)
+ .long SYMBOL_NAME(sys_reboot)
+ .long SYMBOL_NAME(old_readdir)
+ .long SYMBOL_NAME(old_mmap) /* 90 */
+ .long SYMBOL_NAME(sys_munmap)
+ .long SYMBOL_NAME(sys_truncate)
+ .long SYMBOL_NAME(sys_ftruncate)
+ .long SYMBOL_NAME(sys_fchmod)
+ .long SYMBOL_NAME(sys_fchown16) /* 95 */
+ .long SYMBOL_NAME(sys_getpriority)
+ .long SYMBOL_NAME(sys_setpriority)
+ .long SYMBOL_NAME(sys_ni_syscall) /* old profil syscall holder */
+ .long SYMBOL_NAME(sys_statfs)
+ .long SYMBOL_NAME(sys_fstatfs) /* 100 */
+ .long SYMBOL_NAME(sys_ioperm)
+ .long SYMBOL_NAME(sys_socketcall)
+ .long SYMBOL_NAME(sys_syslog)
+ .long SYMBOL_NAME(sys_setitimer)
+ .long SYMBOL_NAME(sys_getitimer) /* 105 */
+ .long SYMBOL_NAME(sys_newstat)
+ .long SYMBOL_NAME(sys_newlstat)
+ .long SYMBOL_NAME(sys_newfstat)
+ .long SYMBOL_NAME(sys_uname)
+ .long SYMBOL_NAME(sys_iopl) /* 110 */
+ .long SYMBOL_NAME(sys_vhangup)
+ .long SYMBOL_NAME(sys_ni_syscall) /* old "idle" system call */
+ .long SYMBOL_NAME(sys_ni_syscall) /* was VM86 */
+ .long SYMBOL_NAME(sys_wait4)
+ .long SYMBOL_NAME(sys_swapoff) /* 115 */
+ .long SYMBOL_NAME(sys_sysinfo)
+ .long SYMBOL_NAME(sys_ipc)
+ .long SYMBOL_NAME(sys_fsync)
+ .long SYMBOL_NAME(sys_sigreturn)
+ .long SYMBOL_NAME(sys_clone) /* 120 */
+ .long SYMBOL_NAME(sys_setdomainname)
+ .long SYMBOL_NAME(sys_newuname)
+ .long SYMBOL_NAME(sys_modify_ldt)
+ .long SYMBOL_NAME(sys_adjtimex)
+ .long SYMBOL_NAME(sys_mprotect) /* 125 */
+ .long SYMBOL_NAME(sys_sigprocmask)
+ .long SYMBOL_NAME(sys_create_module)
+ .long SYMBOL_NAME(sys_init_module)
+ .long SYMBOL_NAME(sys_delete_module)
+ .long SYMBOL_NAME(sys_get_kernel_syms) /* 130 */
+ .long SYMBOL_NAME(sys_quotactl)
+ .long SYMBOL_NAME(sys_getpgid)
+ .long SYMBOL_NAME(sys_fchdir)
+ .long SYMBOL_NAME(sys_bdflush)
+ .long SYMBOL_NAME(sys_sysfs) /* 135 */
+ .long SYMBOL_NAME(sys_personality)
+ .long SYMBOL_NAME(sys_ni_syscall) /* for afs_syscall */
+ .long SYMBOL_NAME(sys_setfsuid16)
+ .long SYMBOL_NAME(sys_setfsgid16)
+ .long SYMBOL_NAME(sys_llseek) /* 140 */
+ .long SYMBOL_NAME(sys_getdents)
+ .long SYMBOL_NAME(sys_select)
+ .long SYMBOL_NAME(sys_flock)
+ .long SYMBOL_NAME(sys_msync)
+ .long SYMBOL_NAME(sys_readv) /* 145 */
+ .long SYMBOL_NAME(sys_writev)
+ .long SYMBOL_NAME(sys_getsid)
+ .long SYMBOL_NAME(sys_fdatasync)
+ .long SYMBOL_NAME(sys_sysctl)
+ .long SYMBOL_NAME(sys_mlock) /* 150 */
+ .long SYMBOL_NAME(sys_munlock)
+ .long SYMBOL_NAME(sys_mlockall)
+ .long SYMBOL_NAME(sys_munlockall)
+ .long SYMBOL_NAME(sys_sched_setparam)
+ .long SYMBOL_NAME(sys_sched_getparam) /* 155 */
+ .long SYMBOL_NAME(sys_sched_setscheduler)
+ .long SYMBOL_NAME(sys_sched_getscheduler)
+ .long SYMBOL_NAME(sys_sched_yield)
+ .long SYMBOL_NAME(sys_sched_get_priority_max)
+ .long SYMBOL_NAME(sys_sched_get_priority_min) /* 160 */
+ .long SYMBOL_NAME(sys_sched_rr_get_interval)
+ .long SYMBOL_NAME(sys_nanosleep)
+ .long SYMBOL_NAME(sys_mremap)
+ .long SYMBOL_NAME(sys_setresuid16)
+ .long SYMBOL_NAME(sys_getresuid16) /* 165 */
+ .long SYMBOL_NAME(sys_ni_syscall) /* was VM86 */
+ .long SYMBOL_NAME(sys_query_module)
+ .long SYMBOL_NAME(sys_poll)
+ .long SYMBOL_NAME(sys_nfsservctl)
+ .long SYMBOL_NAME(sys_setresgid16) /* 170 */
+ .long SYMBOL_NAME(sys_getresgid16)
+ .long SYMBOL_NAME(sys_prctl)
+ .long SYMBOL_NAME(sys_rt_sigreturn)
+ .long SYMBOL_NAME(sys_rt_sigaction)
+ .long SYMBOL_NAME(sys_rt_sigprocmask) /* 175 */
+ .long SYMBOL_NAME(sys_rt_sigpending)
+ .long SYMBOL_NAME(sys_rt_sigtimedwait)
+ .long SYMBOL_NAME(sys_rt_sigqueueinfo)
+ .long SYMBOL_NAME(sys_rt_sigsuspend)
+ .long SYMBOL_NAME(sys_pread) /* 180 */
+ .long SYMBOL_NAME(sys_pwrite)
+ .long SYMBOL_NAME(sys_chown16)
+ .long SYMBOL_NAME(sys_getcwd)
+ .long SYMBOL_NAME(sys_capget)
+ .long SYMBOL_NAME(sys_capset) /* 185 */
+ .long SYMBOL_NAME(sys_sigaltstack)
+ .long SYMBOL_NAME(sys_sendfile)
+ .long SYMBOL_NAME(sys_ni_syscall) /* streams1 */
+ .long SYMBOL_NAME(sys_ni_syscall) /* streams2 */
+ .long SYMBOL_NAME(sys_vfork) /* 190 */
+ .long SYMBOL_NAME(sys_getrlimit)
+ .long SYMBOL_NAME(sys_mmap2)
+ .long SYMBOL_NAME(sys_truncate64)
+ .long SYMBOL_NAME(sys_ftruncate64)
+ .long SYMBOL_NAME(sys_stat64) /* 195 */
+ .long SYMBOL_NAME(sys_lstat64)
+ .long SYMBOL_NAME(sys_fstat64)
+ .long SYMBOL_NAME(sys_lchown)
+ .long SYMBOL_NAME(sys_getuid)
+ .long SYMBOL_NAME(sys_getgid) /* 200 */
+ .long SYMBOL_NAME(sys_geteuid)
+ .long SYMBOL_NAME(sys_getegid)
+ .long SYMBOL_NAME(sys_setreuid)
+ .long SYMBOL_NAME(sys_setregid)
+ .long SYMBOL_NAME(sys_getgroups) /* 205 */
+ .long SYMBOL_NAME(sys_setgroups)
+ .long SYMBOL_NAME(sys_fchown)
+ .long SYMBOL_NAME(sys_setresuid)
+ .long SYMBOL_NAME(sys_getresuid)
+ .long SYMBOL_NAME(sys_setresgid) /* 210 */
+ .long SYMBOL_NAME(sys_getresgid)
+ .long SYMBOL_NAME(sys_chown)
+ .long SYMBOL_NAME(sys_setuid)
+ .long SYMBOL_NAME(sys_setgid)
+ .long SYMBOL_NAME(sys_setfsuid) /* 215 */
+ .long SYMBOL_NAME(sys_setfsgid)
+ .long SYMBOL_NAME(sys_pivot_root)
+ .long SYMBOL_NAME(sys_mincore)
+ .long SYMBOL_NAME(sys_madvise)
+ .long SYMBOL_NAME(sys_getdents64) /* 220 */
+ .long SYMBOL_NAME(sys_fcntl64)
+ .long SYMBOL_NAME(sys_ni_syscall) /* reserved for TUX */
+ .long SYMBOL_NAME(sys_ni_syscall) /* Reserved for Security */
+ .long SYMBOL_NAME(sys_gettid)
+ .long SYMBOL_NAME(sys_readahead) /* 225 */
+ .long SYMBOL_NAME(sys_setxattr)
+ .long SYMBOL_NAME(sys_lsetxattr)
+ .long SYMBOL_NAME(sys_fsetxattr)
+ .long SYMBOL_NAME(sys_getxattr)
+ .long SYMBOL_NAME(sys_lgetxattr) /* 230 */
+ .long SYMBOL_NAME(sys_fgetxattr)
+ .long SYMBOL_NAME(sys_listxattr)
+ .long SYMBOL_NAME(sys_llistxattr)
+ .long SYMBOL_NAME(sys_flistxattr)
+ .long SYMBOL_NAME(sys_removexattr) /* 235 */
+ .long SYMBOL_NAME(sys_lremovexattr)
+ .long SYMBOL_NAME(sys_fremovexattr)
+ .long SYMBOL_NAME(sys_tkill)
+ .long SYMBOL_NAME(sys_sendfile64)
+ .long SYMBOL_NAME(sys_ni_syscall) /* 240 reserved for futex */
+ .long SYMBOL_NAME(sys_ni_syscall) /* reserved for sched_setaffinity */
+ .long SYMBOL_NAME(sys_ni_syscall) /* reserved for sched_getaffinity */
+ .long SYMBOL_NAME(sys_ni_syscall) /* sys_set_thread_area */
+ .long SYMBOL_NAME(sys_ni_syscall) /* sys_get_thread_area */
+ .long SYMBOL_NAME(sys_ni_syscall) /* 245 sys_io_setup */
+ .long SYMBOL_NAME(sys_ni_syscall) /* sys_io_destroy */
+ .long SYMBOL_NAME(sys_ni_syscall) /* sys_io_getevents */
+ .long SYMBOL_NAME(sys_ni_syscall) /* sys_io_submit */
+ .long SYMBOL_NAME(sys_ni_syscall) /* sys_io_cancel */
+ .long SYMBOL_NAME(sys_ni_syscall) /* 250 sys_alloc_hugepages */
+ .long SYMBOL_NAME(sys_ni_syscall) /* sys_free_hugepages */
+ .long SYMBOL_NAME(sys_ni_syscall) /* sys_exit_group */
+ .long SYMBOL_NAME(sys_ni_syscall) /* sys_lookup_dcookie */
+ .long SYMBOL_NAME(sys_ni_syscall) /* sys_epoll_create */
+ .long SYMBOL_NAME(sys_ni_syscall) /* sys_epoll_ctl 255 */
+ .long SYMBOL_NAME(sys_ni_syscall) /* sys_epoll_wait */
+ .long SYMBOL_NAME(sys_ni_syscall) /* sys_remap_file_pages */
+ .long SYMBOL_NAME(sys_ni_syscall) /* sys_set_tid_address */
+
+ .rept NR_syscalls-(.-sys_call_table)/4
+ .long SYMBOL_NAME(sys_ni_syscall)
+ .endr
--- /dev/null
+
+.text
+#include <linux/config.h>
+#include <linux/threads.h>
+#include <linux/linkage.h>
+#include <asm/segment.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/desc.h>
+
+/* Offsets in start_info structure */
+#define SHARED_INFO 4
+#define MOD_START 12
+#define MOD_LEN 16
+
+startup_32:
+ cld
+
+ lss stack_start,%esp
+
+ /* Copy initrd somewhere safe before it's clobbered by BSS. */
+ mov MOD_LEN(%esi),%ecx
+ shr $2,%ecx
+ jz 2f /* bail from copy loop if no initrd */
+ mov $SYMBOL_NAME(_end),%edi
+ add MOD_LEN(%esi),%edi
+ mov MOD_START(%esi),%eax
+ add MOD_LEN(%esi),%eax
+1: sub $4,%eax
+ sub $4,%edi
+ mov (%eax),%ebx
+ mov %ebx,(%edi)
+ loop 1b
+ mov %edi,MOD_START(%esi)
+
+ /* Clear BSS first so that there are no surprises... */
+2: xorl %eax,%eax
+ movl $SYMBOL_NAME(__bss_start),%edi
+ movl $SYMBOL_NAME(_end),%ecx
+ subl %edi,%ecx
+ rep stosb
+
+ /* Copy the necessary stuff from start_info structure. */
+ /* We need to copy shared_info early, so that sti/cli work */
+ mov SHARED_INFO(%esi),%eax
+ mov %eax,SYMBOL_NAME(HYPERVISOR_shared_info)
+ mov $SYMBOL_NAME(start_info_union),%edi
+ mov $128,%ecx
+ rep movsl
+
+ jmp SYMBOL_NAME(start_kernel)
+
+ENTRY(stack_start)
+ .long SYMBOL_NAME(init_task_union)+8192, __KERNEL_DS
+
+.org 0x1000
+ENTRY(empty_zero_page)
+
+.org 0x2000
+ENTRY(default_ldt)
+
+.org 0x3000
+ENTRY(cpu0_pte_quicklist)
+
+.org 0x3400
+ENTRY(cpu0_pgd_quicklist)
+
+.org 0x3800
+ENTRY(stext)
+ENTRY(_stext)
--- /dev/null
+/******************************************************************************
+ * hypervisor.c
+ *
+ * Communication to/from hypervisor.
+ *
+ * Copyright (c) 2002, K A Fraser
+ */
+
+#include <linux/config.h>
+#include <asm/atomic.h>
+#include <linux/irq.h>
+#include <asm/hypervisor.h>
+#include <asm/system.h>
+#include <asm/ptrace.h>
+
+multicall_entry_t multicall_list[8];
+int nr_multicall_ents = 0;
+
+static unsigned long event_mask = 0;
+
+void frobb(void) {}
+
+void do_hypervisor_callback(struct pt_regs *regs)
+{
+ unsigned long events, flags;
+ shared_info_t *shared = HYPERVISOR_shared_info;
+
+ do {
+ /* Specialised local_irq_save(). */
+ flags = test_and_clear_bit(EVENTS_MASTER_ENABLE_BIT,
+ &shared->events_mask);
+ barrier();
+
+ events = xchg(&shared->events, 0);
+ events &= event_mask;
+
+ __asm__ __volatile__ (
+ " push %1 ;"
+ " sub $4,%%esp ;"
+ " jmp 2f ;"
+ "1: btrl %%eax,%0 ;" /* clear bit */
+ " mov %%eax,(%%esp) ;"
+ " call do_IRQ ;" /* do_IRQ(event) */
+ "2: bsfl %0,%%eax ;" /* %eax == bit # */
+ " jnz 1b ;"
+ " add $8,%%esp ;"
+ /* we use %ebx because it is callee-saved */
+ : : "b" (events), "r" (regs)
+ /* clobbered by callback function calls */
+ : "eax", "ecx", "edx", "memory" );
+
+ /* Specialised local_irq_restore(). */
+ if ( flags ) set_bit(EVENTS_MASTER_ENABLE_BIT, &shared->events_mask);
+ barrier();
+ }
+ while ( shared->events );
+}
+
+
+
+/*
+ * Define interface to generic handling in irq.c
+ */
+
+static void shutdown_hypervisor_event(unsigned int irq)
+{
+ clear_bit(irq, &event_mask);
+ clear_bit(irq, &HYPERVISOR_shared_info->events_mask);
+}
+
+static void enable_hypervisor_event(unsigned int irq)
+{
+ set_bit(irq, &event_mask);
+ set_bit(irq, &HYPERVISOR_shared_info->events_mask);
+ if ( test_bit(EVENTS_MASTER_ENABLE_BIT,
+ &HYPERVISOR_shared_info->events_mask) )
+ do_hypervisor_callback(NULL);
+}
+
+static void disable_hypervisor_event(unsigned int irq)
+{
+ clear_bit(irq, &event_mask);
+ clear_bit(irq, &HYPERVISOR_shared_info->events_mask);
+}
+
+static void ack_hypervisor_event(unsigned int irq)
+{
+ if ( !(event_mask & (1<<irq)) )
+ {
+ printk("Unexpected hypervisor event %d\n", irq);
+ atomic_inc(&irq_err_count);
+ }
+ set_bit(irq, &HYPERVISOR_shared_info->events_mask);
+}
+
+static unsigned int startup_hypervisor_event(unsigned int irq)
+{
+ enable_hypervisor_event(irq);
+ return 0;
+}
+
+static void end_hypervisor_event(unsigned int irq)
+{
+}
+
+static struct hw_interrupt_type hypervisor_irq_type = {
+ "Hypervisor-event",
+ startup_hypervisor_event,
+ shutdown_hypervisor_event,
+ enable_hypervisor_event,
+ disable_hypervisor_event,
+ ack_hypervisor_event,
+ end_hypervisor_event,
+ NULL
+};
+
+void __init init_IRQ(void)
+{
+ int i;
+
+ for ( i = 0; i < NR_IRQS; i++ )
+ {
+ irq_desc[i].status = IRQ_DISABLED;
+ irq_desc[i].action = 0;
+ irq_desc[i].depth = 1;
+ irq_desc[i].handler = &hypervisor_irq_type;
+ }
+}
--- /dev/null
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/smp.h>
+#include <linux/user.h>
+#include <linux/elfcore.h>
+#include <linux/mca.h>
+#include <linux/sched.h>
+#include <linux/in6.h>
+#include <linux/interrupt.h>
+#include <linux/smp_lock.h>
+#include <linux/pm.h>
+//XXX ??? #include <linux/pci.h>
+#include <linux/apm_bios.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/tty.h>
+
+#include <asm/semaphore.h>
+#include <asm/processor.h>
+#include <asm/i387.h>
+#include <asm/uaccess.h>
+#include <asm/checksum.h>
+#include <asm/io.h>
+#include <asm/hardirq.h>
+#include <asm/delay.h>
+#include <asm/irq.h>
+#include <asm/mmx.h>
+#include <asm/desc.h>
+#include <asm/pgtable.h>
+#include <asm/pgalloc.h>
+
+extern void dump_thread(struct pt_regs *, struct user *);
+extern spinlock_t rtc_lock;
+
+#if defined(CONFIG_APMXXX) || defined(CONFIG_APM_MODULEXXX)
+extern void machine_real_restart(unsigned char *, int);
+EXPORT_SYMBOL(machine_real_restart);
+extern void default_idle(void);
+EXPORT_SYMBOL(default_idle);
+#endif
+
+#ifdef CONFIG_SMP
+extern void FASTCALL( __write_lock_failed(rwlock_t *rw));
+extern void FASTCALL( __read_lock_failed(rwlock_t *rw));
+#endif
+
+#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_HD) || defined(CONFIG_BLK_DEV_IDE_MODULE) || defined(CONFIG_BLK_DEV_HD_MODULE)
+extern struct drive_info_struct drive_info;
+EXPORT_SYMBOL(drive_info);
+#endif
+
+// XXX extern unsigned long get_cmos_time(void);
+
+/* platform dependent support */
+EXPORT_SYMBOL(boot_cpu_data);
+EXPORT_SYMBOL(__verify_write);
+EXPORT_SYMBOL(dump_thread);
+EXPORT_SYMBOL(dump_fpu);
+EXPORT_SYMBOL(dump_extended_fpu);
+EXPORT_SYMBOL(enable_irq);
+EXPORT_SYMBOL(disable_irq);
+EXPORT_SYMBOL(disable_irq_nosync);
+EXPORT_SYMBOL(probe_irq_mask);
+EXPORT_SYMBOL(kernel_thread);
+EXPORT_SYMBOL(pm_idle);
+EXPORT_SYMBOL(pm_power_off);
+EXPORT_SYMBOL(apm_info);
+//EXPORT_SYMBOL(gdt);
+EXPORT_SYMBOL(empty_zero_page);
+
+#ifdef CONFIG_DEBUG_IOVIRT
+EXPORT_SYMBOL(__io_virt_debug);
+#endif
+
+EXPORT_SYMBOL_NOVERS(__down_failed);
+EXPORT_SYMBOL_NOVERS(__down_failed_interruptible);
+EXPORT_SYMBOL_NOVERS(__down_failed_trylock);
+EXPORT_SYMBOL_NOVERS(__up_wakeup);
+/* Networking helper routines. */
+EXPORT_SYMBOL(csum_partial_copy_generic);
+/* Delay loops */
+EXPORT_SYMBOL(__ndelay);
+EXPORT_SYMBOL(__udelay);
+EXPORT_SYMBOL(__delay);
+EXPORT_SYMBOL(__const_udelay);
+
+EXPORT_SYMBOL_NOVERS(__get_user_1);
+EXPORT_SYMBOL_NOVERS(__get_user_2);
+EXPORT_SYMBOL_NOVERS(__get_user_4);
+
+EXPORT_SYMBOL(strtok);
+EXPORT_SYMBOL(strpbrk);
+EXPORT_SYMBOL(strstr);
+
+EXPORT_SYMBOL(strncpy_from_user);
+EXPORT_SYMBOL(__strncpy_from_user);
+EXPORT_SYMBOL(clear_user);
+EXPORT_SYMBOL(__clear_user);
+EXPORT_SYMBOL(__generic_copy_from_user);
+EXPORT_SYMBOL(__generic_copy_to_user);
+EXPORT_SYMBOL(strnlen_user);
+
+#ifdef CONFIG_X86_USE_3DNOW
+EXPORT_SYMBOL(_mmx_memcpy);
+EXPORT_SYMBOL(mmx_clear_page);
+EXPORT_SYMBOL(mmx_copy_page);
+#endif
+
+#ifdef CONFIG_SMP
+EXPORT_SYMBOL(cpu_data);
+EXPORT_SYMBOL(kernel_flag_cacheline);
+EXPORT_SYMBOL(smp_num_cpus);
+EXPORT_SYMBOL(cpu_online_map);
+EXPORT_SYMBOL_NOVERS(__write_lock_failed);
+EXPORT_SYMBOL_NOVERS(__read_lock_failed);
+
+/* Global SMP irq stuff */
+EXPORT_SYMBOL(synchronize_irq);
+EXPORT_SYMBOL(global_irq_holder);
+EXPORT_SYMBOL(__global_cli);
+EXPORT_SYMBOL(__global_sti);
+EXPORT_SYMBOL(__global_save_flags);
+EXPORT_SYMBOL(__global_restore_flags);
+EXPORT_SYMBOL(smp_call_function);
+
+/* TLB flushing */
+EXPORT_SYMBOL(flush_tlb_page);
+#endif
+
+#ifdef CONFIG_X86_IO_APIC
+EXPORT_SYMBOL(IO_APIC_get_PCI_irq_vector);
+#endif
+
+#ifdef CONFIG_VT
+EXPORT_SYMBOL(screen_info);
+#endif
+
+EXPORT_SYMBOL(get_wchan);
+
+EXPORT_SYMBOL(rtc_lock);
+
+#undef memcpy
+#undef memset
+extern void * memset(void *,int,__kernel_size_t);
+extern void * memcpy(void *,const void *,__kernel_size_t);
+EXPORT_SYMBOL_NOVERS(memcpy);
+EXPORT_SYMBOL_NOVERS(memset);
+
+#ifdef CONFIG_HAVE_DEC_LOCK
+EXPORT_SYMBOL(atomic_dec_and_lock);
+#endif
+
+#ifdef CONFIG_MULTIQUAD
+EXPORT_SYMBOL(xquad_portio);
+#endif
--- /dev/null
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/types.h>
+#include <linux/stddef.h>
+
+
+asmlinkage int sys_ioperm(unsigned long from, unsigned long num, int turn_on)
+{
+ /* No IO permission! Selective IO perms aren't virtualised yet. */
+ return -EPERM;
+}
+
+
+asmlinkage int sys_iopl(unsigned long unused)
+{
+ struct pt_regs *regs = (struct pt_regs *)&unused;
+ unsigned int new_io_pl = regs->ebx & 3;
+ unsigned int old_io_pl = current->thread.io_pl;
+ unsigned int new_hypercall_pl = (regs->ebx >> 2) & 3;
+ unsigned int old_hypercall_pl = current->thread.hypercall_pl;
+
+ /* Need "raw I/O" privileges for direct port access. */
+ if ( (new_io_pl > old_io_pl) &&
+ (!capable(CAP_SYS_RAWIO) || !(start_info.flags & SIF_PRIVILEGED)) )
+ return -EPERM;
+
+ /* Just need generic root/admin privileges for direct hypercall access. */
+ if ( (new_hypercall_pl > old_hypercall_pl) && !capable(CAP_SYS_ADMIN) )
+ return -EPERM;
+
+ /* Maintain OS privileges even if user attempts to relinquish them. */
+ if ( new_hypercall_pl == 0 )
+ new_hypercall_pl = 1;
+ if ( (new_io_pl == 0) && (start_info.flags & SIF_PRIVILEGED) )
+ new_io_pl = 1;
+
+ /* Change our version of the privilege levels. */
+ current->thread.io_pl = new_io_pl;
+ current->thread.hypercall_pl = new_hypercall_pl;
+
+ /* Force the change at ring 0. */
+ HYPERVISOR_set_priv_levels(new_io_pl, new_hypercall_pl);
+
+ return 0;
+}
--- /dev/null
+/*
+ * linux/arch/i386/kernel/irq.c
+ *
+ * Copyright (C) 1992, 1998 Linus Torvalds, Ingo Molnar
+ *
+ * This file contains the code used by various IRQ handling routines:
+ * asking for different IRQ's should be done through these routines
+ * instead of just grabbing them. Thus setups with different IRQ numbers
+ * shouldn't result in any weird surprises, and installing new handlers
+ * should be easier.
+ */
+
+/*
+ * (mostly architecture independent, will move to kernel/irq.c in 2.5.)
+ *
+ * IRQs are in fact implemented a bit like signal handlers for the kernel.
+ * Naturally it's not a 1:1 relation, but there are similarities.
+ */
+
+#include <linux/config.h>
+#include <linux/ptrace.h>
+#include <linux/errno.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/ioport.h>
+#include <linux/interrupt.h>
+#include <linux/timex.h>
+#include <linux/slab.h>
+#include <linux/random.h>
+#include <linux/smp_lock.h>
+#include <linux/init.h>
+#include <linux/kernel_stat.h>
+#include <linux/irq.h>
+#include <linux/proc_fs.h>
+
+#include <asm/atomic.h>
+#include <asm/io.h>
+#include <asm/smp.h>
+#include <asm/system.h>
+#include <asm/bitops.h>
+#include <asm/uaccess.h>
+#include <asm/pgalloc.h>
+#include <asm/delay.h>
+#include <asm/desc.h>
+#include <asm/irq.h>
+
+
+
+/*
+ * Linux has a controller-independent x86 interrupt architecture.
+ * every controller has a 'controller-template', that is used
+ * by the main code to do the right thing. Each driver-visible
+ * interrupt source is transparently wired to the apropriate
+ * controller. Thus drivers need not be aware of the
+ * interrupt-controller.
+ *
+ * Various interrupt controllers we handle: 8259 PIC, SMP IO-APIC,
+ * PIIX4's internal 8259 PIC and SGI's Visual Workstation Cobalt (IO-)APIC.
+ * (IO-APICs assumed to be messaging to Pentium local-APICs)
+ *
+ * the code is designed to be easily extended with new/different
+ * interrupt controllers, without having to do assembly magic.
+ */
+
+/*
+ * Controller mappings for all interrupt sources:
+ */
+irq_desc_t irq_desc[NR_IRQS] __cacheline_aligned =
+ { [0 ... NR_IRQS-1] = { 0, &no_irq_type, NULL, 0, SPIN_LOCK_UNLOCKED}};
+
+static void register_irq_proc (unsigned int irq);
+
+/*
+ * Special irq handlers.
+ */
+
+void no_action(int cpl, void *dev_id, struct pt_regs *regs) { }
+
+/*
+ * Generic no controller code
+ */
+
+static void enable_none(unsigned int irq) { }
+static unsigned int startup_none(unsigned int irq) { return 0; }
+static void disable_none(unsigned int irq) { }
+static void ack_none(unsigned int irq)
+{
+ printk("unexpected IRQ trap at vector %02x\n", irq);
+}
+
+/* startup is the same as "enable", shutdown is same as "disable" */
+#define shutdown_none disable_none
+#define end_none enable_none
+
+struct hw_interrupt_type no_irq_type = {
+ "none",
+ startup_none,
+ shutdown_none,
+ enable_none,
+ disable_none,
+ ack_none,
+ end_none
+};
+
+atomic_t irq_err_count;
+#ifdef CONFIG_X86_IO_APIC
+#ifdef APIC_MISMATCH_DEBUG
+atomic_t irq_mis_count;
+#endif
+#endif
+
+/*
+ * Generic, controller-independent functions:
+ */
+
+int get_irq_list(char *buf)
+{
+ int i, j;
+ struct irqaction * action;
+ char *p = buf;
+
+ p += sprintf(p, " ");
+ for (j=0; j<smp_num_cpus; j++)
+ p += sprintf(p, "CPU%d ",j);
+ *p++ = '\n';
+
+ for (i = 0 ; i < NR_IRQS ; i++) {
+ action = irq_desc[i].action;
+ if (!action)
+ continue;
+ p += sprintf(p, "%3d: ",i);
+#ifndef CONFIG_SMP
+ p += sprintf(p, "%10u ", kstat_irqs(i));
+#else
+ for (j = 0; j < smp_num_cpus; j++)
+ p += sprintf(p, "%10u ",
+ kstat.irqs[cpu_logical_map(j)][i]);
+#endif
+ p += sprintf(p, " %14s", irq_desc[i].handler->typename);
+ p += sprintf(p, " %s", action->name);
+
+ for (action=action->next; action; action = action->next)
+ p += sprintf(p, ", %s", action->name);
+ *p++ = '\n';
+ }
+ p += sprintf(p, "NMI: ");
+ for (j = 0; j < smp_num_cpus; j++)
+ p += sprintf(p, "%10u ",
+ nmi_count(cpu_logical_map(j)));
+ p += sprintf(p, "\n");
+#if CONFIG_X86_LOCAL_APIC
+ p += sprintf(p, "LOC: ");
+ for (j = 0; j < smp_num_cpus; j++)
+ p += sprintf(p, "%10u ",
+ apic_timer_irqs[cpu_logical_map(j)]);
+ p += sprintf(p, "\n");
+#endif
+ p += sprintf(p, "ERR: %10u\n", atomic_read(&irq_err_count));
+#ifdef CONFIG_X86_IO_APIC
+#ifdef APIC_MISMATCH_DEBUG
+ p += sprintf(p, "MIS: %10u\n", atomic_read(&irq_mis_count));
+#endif
+#endif
+ return p - buf;
+}
+
+
+/*
+ * Global interrupt locks for SMP. Allow interrupts to come in on any
+ * CPU, yet make cli/sti act globally to protect critical regions..
+ */
+
+#ifdef CONFIG_SMP
+unsigned char global_irq_holder = NO_PROC_ID;
+unsigned volatile long global_irq_lock; /* pendantic: long for set_bit --RR */
+
+extern void show_stack(unsigned long* esp);
+
+static void show(char * str)
+{
+ int i;
+ int cpu = smp_processor_id();
+
+ printk("\n%s, CPU %d:\n", str, cpu);
+ printk("irq: %d [",irqs_running());
+ for(i=0;i < smp_num_cpus;i++)
+ printk(" %d",local_irq_count(i));
+ printk(" ]\nbh: %d [",spin_is_locked(&global_bh_lock) ? 1 : 0);
+ for(i=0;i < smp_num_cpus;i++)
+ printk(" %d",local_bh_count(i));
+
+ printk(" ]\nStack dumps:");
+ for(i = 0; i < smp_num_cpus; i++) {
+ unsigned long esp;
+ if (i == cpu)
+ continue;
+ printk("\nCPU %d:",i);
+ esp = init_tss[i].esp0;
+ if (!esp) {
+ /* tss->esp0 is set to NULL in cpu_init(),
+ * it's initialized when the cpu returns to user
+ * space. -- manfreds
+ */
+ printk(" <unknown> ");
+ continue;
+ }
+ esp &= ~(THREAD_SIZE-1);
+ esp += sizeof(struct task_struct);
+ show_stack((void*)esp);
+ }
+ printk("\nCPU %d:",cpu);
+ show_stack(NULL);
+ printk("\n");
+}
+
+#define MAXCOUNT 100000000
+
+/*
+ * I had a lockup scenario where a tight loop doing
+ * spin_unlock()/spin_lock() on CPU#1 was racing with
+ * spin_lock() on CPU#0. CPU#0 should have noticed spin_unlock(), but
+ * apparently the spin_unlock() information did not make it
+ * through to CPU#0 ... nasty, is this by design, do we have to limit
+ * 'memory update oscillation frequency' artificially like here?
+ *
+ * Such 'high frequency update' races can be avoided by careful design, but
+ * some of our major constructs like spinlocks use similar techniques,
+ * it would be nice to clarify this issue. Set this define to 0 if you
+ * want to check whether your system freezes. I suspect the delay done
+ * by SYNC_OTHER_CORES() is in correlation with 'snooping latency', but
+ * i thought that such things are guaranteed by design, since we use
+ * the 'LOCK' prefix.
+ */
+#define SUSPECTED_CPU_OR_CHIPSET_BUG_WORKAROUND 0
+
+#if SUSPECTED_CPU_OR_CHIPSET_BUG_WORKAROUND
+# define SYNC_OTHER_CORES(x) udelay(x+1)
+#else
+/*
+ * We have to allow irqs to arrive between __sti and __cli
+ */
+# define SYNC_OTHER_CORES(x) __asm__ __volatile__ ("nop")
+#endif
+
+static inline void wait_on_irq(int cpu)
+{
+ int count = MAXCOUNT;
+
+ for (;;) {
+
+ /*
+ * Wait until all interrupts are gone. Wait
+ * for bottom half handlers unless we're
+ * already executing in one..
+ */
+ if (!irqs_running())
+ if (local_bh_count(cpu) || !spin_is_locked(&global_bh_lock))
+ break;
+
+ /* Duh, we have to loop. Release the lock to avoid deadlocks */
+ clear_bit(0,&global_irq_lock);
+
+ for (;;) {
+ if (!--count) {
+ show("wait_on_irq");
+ count = ~0;
+ }
+ __sti();
+ SYNC_OTHER_CORES(cpu);
+ __cli();
+ if (irqs_running())
+ continue;
+ if (global_irq_lock)
+ continue;
+ if (!local_bh_count(cpu) && spin_is_locked(&global_bh_lock))
+ continue;
+ if (!test_and_set_bit(0,&global_irq_lock))
+ break;
+ }
+ }
+}
+
+/*
+ * This is called when we want to synchronize with
+ * interrupts. We may for example tell a device to
+ * stop sending interrupts: but to make sure there
+ * are no interrupts that are executing on another
+ * CPU we need to call this function.
+ */
+void synchronize_irq(void)
+{
+ if (irqs_running()) {
+ /* Stupid approach */
+ cli();
+ sti();
+ }
+}
+
+static inline void get_irqlock(int cpu)
+{
+ if (test_and_set_bit(0,&global_irq_lock)) {
+ /* do we already hold the lock? */
+ if ((unsigned char) cpu == global_irq_holder)
+ return;
+ /* Uhhuh.. Somebody else got it. Wait.. */
+ do {
+ do {
+ rep_nop();
+ } while (test_bit(0,&global_irq_lock));
+ } while (test_and_set_bit(0,&global_irq_lock));
+ }
+ /*
+ * We also to make sure that nobody else is running
+ * in an interrupt context.
+ */
+ wait_on_irq(cpu);
+
+ /*
+ * Ok, finally..
+ */
+ global_irq_holder = cpu;
+}
+
+void __global_cli(void)
+{
+ panic("__global_cli");
+}
+
+void __global_sti(void)
+{
+ panic("__global_sti");
+}
+
+/*
+ * SMP flags value to restore to:
+ * 0 - global cli
+ * 1 - global sti
+ * 2 - local cli
+ * 3 - local sti
+ */
+unsigned long __global_save_flags(void)
+{
+ panic("__global_save_flags");
+}
+
+void __global_restore_flags(unsigned long flags)
+{
+ panic("__global_restore_flags");
+}
+
+#endif
+
+/*
+ * This should really return information about whether
+ * we should do bottom half handling etc. Right now we
+ * end up _always_ checking the bottom half, which is a
+ * waste of time and is not what some drivers would
+ * prefer.
+ */
+int handle_IRQ_event(unsigned int irq, struct pt_regs * regs, struct irqaction * action)
+{
+ int status;
+ int cpu = smp_processor_id();
+
+ irq_enter(cpu, irq);
+
+ status = 1; /* Force the "do bottom halves" bit */
+
+ if (!(action->flags & SA_INTERRUPT))
+ __sti();
+
+ do {
+ status |= action->flags;
+ action->handler(irq, action->dev_id, regs);
+ action = action->next;
+ } while (action);
+ if (status & SA_SAMPLE_RANDOM)
+ add_interrupt_randomness(irq);
+ __cli();
+
+ irq_exit(cpu, irq);
+
+ return status;
+}
+
+/*
+ * Generic enable/disable code: this just calls
+ * down into the PIC-specific version for the actual
+ * hardware disable after having gotten the irq
+ * controller lock.
+ */
+
+/**
+ * disable_irq_nosync - disable an irq without waiting
+ * @irq: Interrupt to disable
+ *
+ * Disable the selected interrupt line. Disables and Enables are
+ * nested.
+ * Unlike disable_irq(), this function does not ensure existing
+ * instances of the IRQ handler have completed before returning.
+ *
+ * This function may be called from IRQ context.
+ */
+
+inline void disable_irq_nosync(unsigned int irq)
+{
+ irq_desc_t *desc = irq_desc + irq;
+ unsigned long flags;
+
+ spin_lock_irqsave(&desc->lock, flags);
+ if (!desc->depth++) {
+ desc->status |= IRQ_DISABLED;
+ desc->handler->disable(irq);
+ }
+ spin_unlock_irqrestore(&desc->lock, flags);
+}
+
+/**
+ * disable_irq - disable an irq and wait for completion
+ * @irq: Interrupt to disable
+ *
+ * Disable the selected interrupt line. Enables and Disables are
+ * nested.
+ * This function waits for any pending IRQ handlers for this interrupt
+ * to complete before returning. If you use this function while
+ * holding a resource the IRQ handler may need you will deadlock.
+ *
+ * This function may be called - with care - from IRQ context.
+ */
+
+void disable_irq(unsigned int irq)
+{
+ disable_irq_nosync(irq);
+
+ if (!local_irq_count(smp_processor_id())) {
+ do {
+ barrier();
+ cpu_relax();
+ } while (irq_desc[irq].status & IRQ_INPROGRESS);
+ }
+}
+
+/**
+ * enable_irq - enable handling of an irq
+ * @irq: Interrupt to enable
+ *
+ * Undoes the effect of one call to disable_irq(). If this
+ * matches the last disable, processing of interrupts on this
+ * IRQ line is re-enabled.
+ *
+ * This function may be called from IRQ context.
+ */
+
+void enable_irq(unsigned int irq)
+{
+ irq_desc_t *desc = irq_desc + irq;
+ unsigned long flags;
+
+ spin_lock_irqsave(&desc->lock, flags);
+ switch (desc->depth) {
+ case 1: {
+ unsigned int status = desc->status & ~IRQ_DISABLED;
+ desc->status = status;
+ if ((status & (IRQ_PENDING | IRQ_REPLAY)) == IRQ_PENDING) {
+ desc->status = status | IRQ_REPLAY;
+ hw_resend_irq(desc->handler,irq);
+ }
+ desc->handler->enable(irq);
+ /* fall-through */
+ }
+ default:
+ desc->depth--;
+ break;
+ case 0:
+ printk("enable_irq(%u) unbalanced from %p\n", irq,
+ __builtin_return_address(0));
+ }
+ spin_unlock_irqrestore(&desc->lock, flags);
+}
+
+/*
+ * do_IRQ handles all normal device IRQ's (the special
+ * SMP cross-CPU interrupts have their own specific
+ * handlers).
+ */
+asmlinkage unsigned int do_IRQ(int irq, struct pt_regs *regs)
+{
+ /*
+ * We ack quickly, we don't want the irq controller
+ * thinking we're snobs just because some other CPU has
+ * disabled global interrupts (we have already done the
+ * INT_ACK cycles, it's too late to try to pretend to the
+ * controller that we aren't taking the interrupt).
+ *
+ * 0 return value means that this irq is already being
+ * handled by some other CPU. (or is disabled)
+ */
+ int cpu = smp_processor_id();
+ irq_desc_t *desc = irq_desc + irq;
+ struct irqaction * action;
+ unsigned int status;
+#ifdef CONFIG_DEBUG_STACKOVERFLOW
+ long esp;
+
+ /* Debugging check for stack overflow: is there less than 1KB free? */
+ __asm__ __volatile__("andl %%esp,%0" : "=r" (esp) : "0" (8191));
+ if (unlikely(esp < (sizeof(struct task_struct) + 1024))) {
+ extern void show_stack(unsigned long *);
+
+ printk("do_IRQ: stack overflow: %ld\n",
+ esp - sizeof(struct task_struct));
+ __asm__ __volatile__("movl %%esp,%0" : "=r" (esp));
+ show_stack((void *)esp);
+ }
+#endif
+
+ kstat.irqs[cpu][irq]++;
+ spin_lock(&desc->lock);
+ desc->handler->ack(irq);
+ /*
+ REPLAY is when Linux resends an IRQ that was dropped earlier
+ WAITING is used by probe to mark irqs that are being tested
+ */
+ status = desc->status & ~(IRQ_REPLAY | IRQ_WAITING);
+ status |= IRQ_PENDING; /* we _want_ to handle it */
+
+ /*
+ * If the IRQ is disabled for whatever reason, we cannot
+ * use the action we have.
+ */
+ action = NULL;
+ if (!(status & (IRQ_DISABLED | IRQ_INPROGRESS))) {
+ action = desc->action;
+ status &= ~IRQ_PENDING; /* we commit to handling */
+ status |= IRQ_INPROGRESS; /* we are handling it */
+ }
+ desc->status = status;
+
+ /*
+ * If there is no IRQ handler or it was disabled, exit early.
+ Since we set PENDING, if another processor is handling
+ a different instance of this same irq, the other processor
+ will take care of it.
+ */
+ if (!action)
+ goto out;
+
+ /*
+ * Edge triggered interrupts need to remember
+ * pending events.
+ * This applies to any hw interrupts that allow a second
+ * instance of the same irq to arrive while we are in do_IRQ
+ * or in the handler. But the code here only handles the _second_
+ * instance of the irq, not the third or fourth. So it is mostly
+ * useful for irq hardware that does not mask cleanly in an
+ * SMP environment.
+ */
+ for (;;) {
+ spin_unlock(&desc->lock);
+ handle_IRQ_event(irq, regs, action);
+ spin_lock(&desc->lock);
+
+ if (!(desc->status & IRQ_PENDING))
+ break;
+ desc->status &= ~IRQ_PENDING;
+ }
+ desc->status &= ~IRQ_INPROGRESS;
+out:
+ /*
+ * The ->end() handler has to deal with interrupts which got
+ * disabled while the handler was running.
+ */
+ desc->handler->end(irq);
+ spin_unlock(&desc->lock);
+
+ if (softirq_pending(cpu))
+ do_softirq();
+ return 1;
+}
+
+/**
+ * request_irq - allocate an interrupt line
+ * @irq: Interrupt line to allocate
+ * @handler: Function to be called when the IRQ occurs
+ * @irqflags: Interrupt type flags
+ * @devname: An ascii name for the claiming device
+ * @dev_id: A cookie passed back to the handler function
+ *
+ * This call allocates interrupt resources and enables the
+ * interrupt line and IRQ handling. From the point this
+ * call is made your handler function may be invoked. Since
+ * your handler function must clear any interrupt the board
+ * raises, you must take care both to initialise your hardware
+ * and to set up the interrupt handler in the right order.
+ *
+ * Dev_id must be globally unique. Normally the address of the
+ * device data structure is used as the cookie. Since the handler
+ * receives this value it makes sense to use it.
+ *
+ * If your interrupt is shared you must pass a non NULL dev_id
+ * as this is required when freeing the interrupt.
+ *
+ * Flags:
+ *
+ * SA_SHIRQ Interrupt is shared
+ *
+ * SA_INTERRUPT Disable local interrupts while processing
+ *
+ * SA_SAMPLE_RANDOM The interrupt can be used for entropy
+ *
+ */
+
+int request_irq(unsigned int irq,
+ void (*handler)(int, void *, struct pt_regs *),
+ unsigned long irqflags,
+ const char * devname,
+ void *dev_id)
+{
+ int retval;
+ struct irqaction * action;
+
+#if 1
+ /*
+ * Sanity-check: shared interrupts should REALLY pass in
+ * a real dev-ID, otherwise we'll have trouble later trying
+ * to figure out which interrupt is which (messes up the
+ * interrupt freeing logic etc).
+ */
+ if (irqflags & SA_SHIRQ) {
+ if (!dev_id)
+ printk("Bad boy: %s (at 0x%x) called us without a dev_id!\n", devname, (&irq)[-1]);
+ }
+#endif
+
+ if (irq >= NR_IRQS)
+ return -EINVAL;
+ if (!handler)
+ return -EINVAL;
+
+ action = (struct irqaction *)
+ kmalloc(sizeof(struct irqaction), GFP_KERNEL);
+ if (!action)
+ return -ENOMEM;
+
+ action->handler = handler;
+ action->flags = irqflags;
+ action->mask = 0;
+ action->name = devname;
+ action->next = NULL;
+ action->dev_id = dev_id;
+
+ retval = setup_irq(irq, action);
+ if (retval)
+ kfree(action);
+ return retval;
+}
+
+/**
+ * free_irq - free an interrupt
+ * @irq: Interrupt line to free
+ * @dev_id: Device identity to free
+ *
+ * Remove an interrupt handler. The handler is removed and if the
+ * interrupt line is no longer in use by any driver it is disabled.
+ * On a shared IRQ the caller must ensure the interrupt is disabled
+ * on the card it drives before calling this function. The function
+ * does not return until any executing interrupts for this IRQ
+ * have completed.
+ *
+ * This function may be called from interrupt context.
+ *
+ * Bugs: Attempting to free an irq in a handler for the same irq hangs
+ * the machine.
+ */
+
+void free_irq(unsigned int irq, void *dev_id)
+{
+ irq_desc_t *desc;
+ struct irqaction **p;
+ unsigned long flags;
+
+ if (irq >= NR_IRQS)
+ return;
+
+ desc = irq_desc + irq;
+ spin_lock_irqsave(&desc->lock,flags);
+ p = &desc->action;
+ for (;;) {
+ struct irqaction * action = *p;
+ if (action) {
+ struct irqaction **pp = p;
+ p = &action->next;
+ if (action->dev_id != dev_id)
+ continue;
+
+ /* Found it - now remove it from the list of entries */
+ *pp = action->next;
+ if (!desc->action) {
+ desc->status |= IRQ_DISABLED;
+ desc->handler->shutdown(irq);
+ }
+ spin_unlock_irqrestore(&desc->lock,flags);
+
+#ifdef CONFIG_SMP
+ /* Wait to make sure it's not being used on another CPU */
+ while (desc->status & IRQ_INPROGRESS) {
+ barrier();
+ cpu_relax();
+ }
+#endif
+ kfree(action);
+ return;
+ }
+ printk("Trying to free free IRQ%d\n",irq);
+ spin_unlock_irqrestore(&desc->lock,flags);
+ return;
+ }
+}
+
+/*
+ * IRQ autodetection code..
+ *
+ * This depends on the fact that any interrupt that
+ * comes in on to an unassigned handler will get stuck
+ * with "IRQ_WAITING" cleared and the interrupt
+ * disabled.
+ */
+
+static DECLARE_MUTEX(probe_sem);
+
+/**
+ * probe_irq_on - begin an interrupt autodetect
+ *
+ * Commence probing for an interrupt. The interrupts are scanned
+ * and a mask of potential interrupt lines is returned.
+ *
+ */
+
+unsigned long probe_irq_on(void)
+{
+ unsigned int i;
+ irq_desc_t *desc;
+ unsigned long val;
+ unsigned long delay;
+
+ down(&probe_sem);
+ /*
+ * something may have generated an irq long ago and we want to
+ * flush such a longstanding irq before considering it as spurious.
+ */
+ for (i = NR_IRQS-1; i > 0; i--) {
+ desc = irq_desc + i;
+
+ spin_lock_irq(&desc->lock);
+ if (!irq_desc[i].action)
+ irq_desc[i].handler->startup(i);
+ spin_unlock_irq(&desc->lock);
+ }
+
+ /* Wait for longstanding interrupts to trigger. */
+ for (delay = jiffies + HZ/50; time_after(delay, jiffies); )
+ /* about 20ms delay */ synchronize_irq();
+
+ /*
+ * enable any unassigned irqs
+ * (we must startup again here because if a longstanding irq
+ * happened in the previous stage, it may have masked itself)
+ */
+ for (i = NR_IRQS-1; i > 0; i--) {
+ desc = irq_desc + i;
+
+ spin_lock_irq(&desc->lock);
+ if (!desc->action) {
+ desc->status |= IRQ_AUTODETECT | IRQ_WAITING;
+ if (desc->handler->startup(i))
+ desc->status |= IRQ_PENDING;
+ }
+ spin_unlock_irq(&desc->lock);
+ }
+
+ /*
+ * Wait for spurious interrupts to trigger
+ */
+ for (delay = jiffies + HZ/10; time_after(delay, jiffies); )
+ /* about 100ms delay */ synchronize_irq();
+
+ /*
+ * Now filter out any obviously spurious interrupts
+ */
+ val = 0;
+ for (i = 0; i < NR_IRQS; i++) {
+ irq_desc_t *desc = irq_desc + i;
+ unsigned int status;
+
+ spin_lock_irq(&desc->lock);
+ status = desc->status;
+
+ if (status & IRQ_AUTODETECT) {
+ /* It triggered already - consider it spurious. */
+ if (!(status & IRQ_WAITING)) {
+ desc->status = status & ~IRQ_AUTODETECT;
+ desc->handler->shutdown(i);
+ } else
+ if (i < 32)
+ val |= 1 << i;
+ }
+ spin_unlock_irq(&desc->lock);
+ }
+
+ return val;
+}
+
+/*
+ * Return a mask of triggered interrupts (this
+ * can handle only legacy ISA interrupts).
+ */
+
+/**
+ * probe_irq_mask - scan a bitmap of interrupt lines
+ * @val: mask of interrupts to consider
+ *
+ * Scan the ISA bus interrupt lines and return a bitmap of
+ * active interrupts. The interrupt probe logic state is then
+ * returned to its previous value.
+ *
+ * Note: we need to scan all the irq's even though we will
+ * only return ISA irq numbers - just so that we reset them
+ * all to a known state.
+ */
+unsigned int probe_irq_mask(unsigned long val)
+{
+ int i;
+ unsigned int mask;
+
+ mask = 0;
+ for (i = 0; i < NR_IRQS; i++) {
+ irq_desc_t *desc = irq_desc + i;
+ unsigned int status;
+
+ spin_lock_irq(&desc->lock);
+ status = desc->status;
+
+ if (status & IRQ_AUTODETECT) {
+ if (i < 16 && !(status & IRQ_WAITING))
+ mask |= 1 << i;
+
+ desc->status = status & ~IRQ_AUTODETECT;
+ desc->handler->shutdown(i);
+ }
+ spin_unlock_irq(&desc->lock);
+ }
+ up(&probe_sem);
+
+ return mask & val;
+}
+
+/*
+ * Return the one interrupt that triggered (this can
+ * handle any interrupt source).
+ */
+
+/**
+ * probe_irq_off - end an interrupt autodetect
+ * @val: mask of potential interrupts (unused)
+ *
+ * Scans the unused interrupt lines and returns the line which
+ * appears to have triggered the interrupt. If no interrupt was
+ * found then zero is returned. If more than one interrupt is
+ * found then minus the first candidate is returned to indicate
+ * their is doubt.
+ *
+ * The interrupt probe logic state is returned to its previous
+ * value.
+ *
+ * BUGS: When used in a module (which arguably shouldnt happen)
+ * nothing prevents two IRQ probe callers from overlapping. The
+ * results of this are non-optimal.
+ */
+
+int probe_irq_off(unsigned long val)
+{
+ int i, irq_found, nr_irqs;
+
+ nr_irqs = 0;
+ irq_found = 0;
+ for (i = 0; i < NR_IRQS; i++) {
+ irq_desc_t *desc = irq_desc + i;
+ unsigned int status;
+
+ spin_lock_irq(&desc->lock);
+ status = desc->status;
+
+ if (status & IRQ_AUTODETECT) {
+ if (!(status & IRQ_WAITING)) {
+ if (!nr_irqs)
+ irq_found = i;
+ nr_irqs++;
+ }
+ desc->status = status & ~IRQ_AUTODETECT;
+ desc->handler->shutdown(i);
+ }
+ spin_unlock_irq(&desc->lock);
+ }
+ up(&probe_sem);
+
+ if (nr_irqs > 1)
+ irq_found = -irq_found;
+ return irq_found;
+}
+
+/* this was setup_x86_irq but it seems pretty generic */
+int setup_irq(unsigned int irq, struct irqaction * new)
+{
+ int shared = 0;
+ unsigned long flags;
+ struct irqaction *old, **p;
+ irq_desc_t *desc = irq_desc + irq;
+
+ /*
+ * Some drivers like serial.c use request_irq() heavily,
+ * so we have to be careful not to interfere with a
+ * running system.
+ */
+ if (new->flags & SA_SAMPLE_RANDOM) {
+ /*
+ * This function might sleep, we want to call it first,
+ * outside of the atomic block.
+ * Yes, this might clear the entropy pool if the wrong
+ * driver is attempted to be loaded, without actually
+ * installing a new handler, but is this really a problem,
+ * only the sysadmin is able to do this.
+ */
+ rand_initialize_irq(irq);
+ }
+
+ /*
+ * The following block of code has to be executed atomically
+ */
+ spin_lock_irqsave(&desc->lock,flags);
+ p = &desc->action;
+ if ((old = *p) != NULL) {
+ /* Can't share interrupts unless both agree to */
+ if (!(old->flags & new->flags & SA_SHIRQ)) {
+ spin_unlock_irqrestore(&desc->lock,flags);
+ return -EBUSY;
+ }
+
+ /* add new interrupt at end of irq queue */
+ do {
+ p = &old->next;
+ old = *p;
+ } while (old);
+ shared = 1;
+ }
+
+ *p = new;
+
+ if (!shared) {
+ desc->depth = 0;
+ desc->status &= ~(IRQ_DISABLED | IRQ_AUTODETECT | IRQ_WAITING);
+ desc->handler->startup(irq);
+ }
+ spin_unlock_irqrestore(&desc->lock,flags);
+
+ register_irq_proc(irq);
+ return 0;
+}
+
+static struct proc_dir_entry * root_irq_dir;
+static struct proc_dir_entry * irq_dir [NR_IRQS];
+
+#define HEX_DIGITS 8
+
+static unsigned int parse_hex_value (const char *buffer,
+ unsigned long count, unsigned long *ret)
+{
+ unsigned char hexnum [HEX_DIGITS];
+ unsigned long value;
+ int i;
+
+ if (!count)
+ return -EINVAL;
+ if (count > HEX_DIGITS)
+ count = HEX_DIGITS;
+ if (copy_from_user(hexnum, buffer, count))
+ return -EFAULT;
+
+ /*
+ * Parse the first 8 characters as a hex string, any non-hex char
+ * is end-of-string. '00e1', 'e1', '00E1', 'E1' are all the same.
+ */
+ value = 0;
+
+ for (i = 0; i < count; i++) {
+ unsigned int c = hexnum[i];
+
+ switch (c) {
+ case '0' ... '9': c -= '0'; break;
+ case 'a' ... 'f': c -= 'a'-10; break;
+ case 'A' ... 'F': c -= 'A'-10; break;
+ default:
+ goto out;
+ }
+ value = (value << 4) | c;
+ }
+out:
+ *ret = value;
+ return 0;
+}
+
+#if CONFIG_SMP
+
+static struct proc_dir_entry * smp_affinity_entry [NR_IRQS];
+
+static unsigned long irq_affinity [NR_IRQS] = { [0 ... NR_IRQS-1] = ~0UL };
+static int irq_affinity_read_proc (char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ if (count < HEX_DIGITS+1)
+ return -EINVAL;
+ return sprintf (page, "%08lx\n", irq_affinity[(long)data]);
+}
+
+static int irq_affinity_write_proc (struct file *file, const char *buffer,
+ unsigned long count, void *data)
+{
+ int irq = (long) data, full_count = count, err;
+ unsigned long new_value;
+
+ if (!irq_desc[irq].handler->set_affinity)
+ return -EIO;
+
+ err = parse_hex_value(buffer, count, &new_value);
+
+ /*
+ * Do not allow disabling IRQs completely - it's a too easy
+ * way to make the system unusable accidentally :-) At least
+ * one online CPU still has to be targeted.
+ */
+ if (!(new_value & cpu_online_map))
+ return -EINVAL;
+
+ irq_affinity[irq] = new_value;
+ irq_desc[irq].handler->set_affinity(irq, new_value);
+
+ return full_count;
+}
+
+#endif
+
+static int prof_cpu_mask_read_proc (char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ unsigned long *mask = (unsigned long *) data;
+ if (count < HEX_DIGITS+1)
+ return -EINVAL;
+ return sprintf (page, "%08lx\n", *mask);
+}
+
+static int prof_cpu_mask_write_proc (struct file *file, const char *buffer,
+ unsigned long count, void *data)
+{
+ unsigned long *mask = (unsigned long *) data, full_count = count, err;
+ unsigned long new_value;
+
+ err = parse_hex_value(buffer, count, &new_value);
+ if (err)
+ return err;
+
+ *mask = new_value;
+ return full_count;
+}
+
+#define MAX_NAMELEN 10
+
+static void register_irq_proc (unsigned int irq)
+{
+ char name [MAX_NAMELEN];
+
+ if (!root_irq_dir || (irq_desc[irq].handler == &no_irq_type) ||
+ irq_dir[irq])
+ return;
+
+ memset(name, 0, MAX_NAMELEN);
+ sprintf(name, "%d", irq);
+
+ /* create /proc/irq/1234 */
+ irq_dir[irq] = proc_mkdir(name, root_irq_dir);
+
+#if CONFIG_SMP
+ {
+ struct proc_dir_entry *entry;
+
+ /* create /proc/irq/1234/smp_affinity */
+ entry = create_proc_entry("smp_affinity", 0600, irq_dir[irq]);
+
+ if (entry) {
+ entry->nlink = 1;
+ entry->data = (void *)(long)irq;
+ entry->read_proc = irq_affinity_read_proc;
+ entry->write_proc = irq_affinity_write_proc;
+ }
+
+ smp_affinity_entry[irq] = entry;
+ }
+#endif
+}
+
+unsigned long prof_cpu_mask = -1;
+
+void init_irq_proc (void)
+{
+ struct proc_dir_entry *entry;
+ int i;
+
+ /* create /proc/irq */
+ root_irq_dir = proc_mkdir("irq", 0);
+
+ /* create /proc/irq/prof_cpu_mask */
+ entry = create_proc_entry("prof_cpu_mask", 0600, root_irq_dir);
+
+ if (!entry)
+ return;
+
+ entry->nlink = 1;
+ entry->data = (void *)&prof_cpu_mask;
+ entry->read_proc = prof_cpu_mask_read_proc;
+ entry->write_proc = prof_cpu_mask_write_proc;
+
+ /*
+ * Create entries for all existing IRQs.
+ */
+ for (i = 0; i < NR_IRQS; i++)
+ register_irq_proc(i);
+}
+
--- /dev/null
+/*
+ * linux/kernel/ldt.c
+ *
+ * Copyright (C) 1992 Krishna Balasubramanian and Linus Torvalds
+ * Copyright (C) 1999 Ingo Molnar <mingo@redhat.com>
+ */
+
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
+#include <linux/vmalloc.h>
+
+#include <asm/uaccess.h>
+#include <asm/system.h>
+#include <asm/ldt.h>
+#include <asm/desc.h>
+
+/*
+ * read_ldt() is not really atomic - this is not a problem since
+ * synchronization of reads and writes done to the LDT has to be
+ * assured by user-space anyway. Writes are atomic, to protect
+ * the security checks done on new descriptors.
+ */
+static int read_ldt(void * ptr, unsigned long bytecount)
+{
+ int err;
+ unsigned long size;
+ struct mm_struct * mm = current->mm;
+
+ err = 0;
+ if (!mm->context.segments)
+ goto out;
+
+ size = LDT_ENTRIES*LDT_ENTRY_SIZE;
+ if (size > bytecount)
+ size = bytecount;
+
+ err = size;
+ if (copy_to_user(ptr, mm->context.segments, size))
+ err = -EFAULT;
+ out:
+ return err;
+}
+
+static int read_default_ldt(void * ptr, unsigned long bytecount)
+{
+ int err;
+ unsigned long size;
+ void *address;
+
+ err = 0;
+ address = &default_ldt[0];
+ size = sizeof(struct desc_struct);
+ if (size > bytecount)
+ size = bytecount;
+
+ err = size;
+ if (copy_to_user(ptr, address, size))
+ err = -EFAULT;
+
+ return err;
+}
+
+static int write_ldt(void * ptr, unsigned long bytecount, int oldmode)
+{
+ struct mm_struct * mm = current->mm;
+ __u32 entry_1, entry_2, *lp;
+ unsigned long phys_lp;
+ int error;
+ struct modify_ldt_ldt_s ldt_info;
+
+ error = -EINVAL;
+ if (bytecount != sizeof(ldt_info))
+ goto out;
+ error = -EFAULT;
+ if (copy_from_user(&ldt_info, ptr, sizeof(ldt_info)))
+ goto out;
+
+ error = -EINVAL;
+ if (ldt_info.entry_number >= LDT_ENTRIES)
+ goto out;
+ if (ldt_info.contents == 3) {
+ if (oldmode)
+ goto out;
+ if (ldt_info.seg_not_present == 0)
+ goto out;
+ }
+
+ down_write(&mm->mmap_sem);
+ if (!mm->context.segments) {
+ void * segments = vmalloc(LDT_ENTRIES*LDT_ENTRY_SIZE);
+ error = -ENOMEM;
+ if (!segments)
+ goto out_unlock;
+ memset(segments, 0, LDT_ENTRIES*LDT_ENTRY_SIZE);
+ make_pages_readonly(segments, (LDT_ENTRIES*LDT_ENTRY_SIZE)/PAGE_SIZE);
+ wmb();
+ mm->context.segments = segments;
+ mm->context.cpuvalid = 1UL << smp_processor_id();
+ load_LDT(mm);
+ flush_page_update_queue();
+ }
+
+ lp = (__u32 *)((ldt_info.entry_number<<3) + (char *)mm->context.segments);
+ phys_lp = arbitrary_virt_to_phys(lp);
+
+ /* Allow LDTs to be cleared by the user. */
+ if (ldt_info.base_addr == 0 && ldt_info.limit == 0) {
+ if (oldmode ||
+ (ldt_info.contents == 0 &&
+ ldt_info.read_exec_only == 1 &&
+ ldt_info.seg_32bit == 0 &&
+ ldt_info.limit_in_pages == 0 &&
+ ldt_info.seg_not_present == 1 &&
+ ldt_info.useable == 0 )) {
+ entry_1 = 0;
+ entry_2 = 0;
+ goto install;
+ }
+ }
+
+ entry_1 = ((ldt_info.base_addr & 0x0000ffff) << 16) |
+ (ldt_info.limit & 0x0ffff);
+ entry_2 = (ldt_info.base_addr & 0xff000000) |
+ ((ldt_info.base_addr & 0x00ff0000) >> 16) |
+ (ldt_info.limit & 0xf0000) |
+ ((ldt_info.read_exec_only ^ 1) << 9) |
+ (ldt_info.contents << 10) |
+ ((ldt_info.seg_not_present ^ 1) << 15) |
+ (ldt_info.seg_32bit << 22) |
+ (ldt_info.limit_in_pages << 23) |
+ 0x7000;
+ if (!oldmode)
+ entry_2 |= (ldt_info.useable << 20);
+
+ /* Install the new entry ... */
+ install:
+ HYPERVISOR_update_descriptor(phys_lp, entry_1, entry_2);
+ error = 0;
+
+ out_unlock:
+ up_write(&mm->mmap_sem);
+ out:
+ return error;
+}
+
+asmlinkage int sys_modify_ldt(int func, void *ptr, unsigned long bytecount)
+{
+ int ret = -ENOSYS;
+
+ switch (func) {
+ case 0:
+ ret = read_ldt(ptr, bytecount);
+ break;
+ case 1:
+ ret = write_ldt(ptr, bytecount, 1);
+ break;
+ case 2:
+ ret = read_default_ldt(ptr, bytecount);
+ break;
+ case 0x11:
+ ret = write_ldt(ptr, bytecount, 0);
+ break;
+ }
+ return ret;
+}
--- /dev/null
+/*
+ * linux/arch/i386/kernel/process.c
+ *
+ * Copyright (C) 1995 Linus Torvalds
+ *
+ * Pentium III FXSR, SSE support
+ * Gareth Hughes <gareth@valinux.com>, May 2000
+ */
+
+/*
+ * This file handles the architecture-dependent parts of process handling..
+ */
+
+#define __KERNEL_SYSCALLS__
+#include <stdarg.h>
+
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
+#include <linux/stddef.h>
+#include <linux/unistd.h>
+#include <linux/ptrace.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+#include <linux/user.h>
+#include <linux/a.out.h>
+#include <linux/interrupt.h>
+#include <linux/config.h>
+#include <linux/delay.h>
+#include <linux/reboot.h>
+#include <linux/init.h>
+#include <linux/mc146818rtc.h>
+
+#include <asm/uaccess.h>
+#include <asm/pgtable.h>
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/ldt.h>
+#include <asm/processor.h>
+#include <asm/i387.h>
+#include <asm/desc.h>
+#include <asm/mmu_context.h>
+#include <asm/multicall.h>
+
+#include <linux/irq.h>
+
+asmlinkage void ret_from_fork(void) __asm__("ret_from_fork");
+
+int hlt_counter;
+
+/*
+ * Powermanagement idle function, if any..
+ */
+void (*pm_idle)(void);
+
+/*
+ * Power off function, if any
+ */
+void (*pm_power_off)(void);
+
+void disable_hlt(void)
+{
+ hlt_counter++;
+}
+
+void enable_hlt(void)
+{
+ hlt_counter--;
+}
+
+/*
+ * The idle thread. There's no useful work to be
+ * done, so just try to conserve power and have a
+ * low exit latency (ie sit in a loop waiting for
+ * somebody to say that they'd like to reschedule)
+ */
+void cpu_idle (void)
+{
+ /* endless idle loop with no priority at all */
+ init_idle();
+ current->nice = 20;
+ current->counter = -100;
+
+ while (1) {
+ while (!current->need_resched)
+ HYPERVISOR_yield();
+ schedule();
+ check_pgt_cache();
+ }
+}
+
+void machine_restart(char * __unused)
+{
+ HYPERVISOR_exit();
+}
+
+void machine_halt(void)
+{
+ HYPERVISOR_exit();
+}
+
+void machine_power_off(void)
+{
+ HYPERVISOR_exit();
+}
+
+extern void show_trace(unsigned long* esp);
+
+void show_regs(struct pt_regs * regs)
+{
+ printk("\n");
+ printk("Pid: %d, comm: %20s\n", current->pid, current->comm);
+ printk("EIP: %04x:[<%08lx>] CPU: %d",0xffff & regs->xcs,regs->eip, smp_processor_id());
+ if (regs->xcs & 2)
+ printk(" ESP: %04x:%08lx",0xffff & regs->xss,regs->esp);
+ printk(" EFLAGS: %08lx %s\n",regs->eflags, print_tainted());
+ printk("EAX: %08lx EBX: %08lx ECX: %08lx EDX: %08lx\n",
+ regs->eax,regs->ebx,regs->ecx,regs->edx);
+ printk("ESI: %08lx EDI: %08lx EBP: %08lx",
+ regs->esi, regs->edi, regs->ebp);
+ printk(" DS: %04x ES: %04x\n",
+ 0xffff & regs->xds,0xffff & regs->xes);
+
+ show_trace(®s->esp);
+}
+
+/*
+ * No need to lock the MM as we are the last user
+ */
+void release_segments(struct mm_struct *mm)
+{
+ void * ldt = mm->context.segments;
+
+ /*
+ * free the LDT
+ */
+ if (ldt) {
+ mm->context.segments = NULL;
+ clear_LDT();
+ make_pages_writeable(ldt, (LDT_ENTRIES*LDT_ENTRY_SIZE)/PAGE_SIZE);
+ flush_page_update_queue();
+ vfree(ldt);
+ }
+}
+
+/*
+ * Create a kernel thread
+ */
+int arch_kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
+{
+ long retval, d0;
+
+ __asm__ __volatile__(
+ "movl %%esp,%%esi\n\t"
+ "int $0x80\n\t" /* Linux/i386 system call */
+ "cmpl %%esp,%%esi\n\t" /* child or parent? */
+ "je 1f\n\t" /* parent - jump */
+ /* Load the argument into eax, and push it. That way, it does
+ * not matter whether the called function is compiled with
+ * -mregparm or not. */
+ "movl %4,%%eax\n\t"
+ "pushl %%eax\n\t"
+ "call *%5\n\t" /* call fn */
+ "movl %3,%0\n\t" /* exit */
+ "int $0x80\n"
+ "1:\t"
+ :"=&a" (retval), "=&S" (d0)
+ :"0" (__NR_clone), "i" (__NR_exit),
+ "r" (arg), "r" (fn),
+ "b" (flags | CLONE_VM)
+ : "memory");
+
+ return retval;
+}
+
+/*
+ * Free current thread data structures etc..
+ */
+void exit_thread(void)
+{
+ /* nothing to do ... */
+}
+
+void flush_thread(void)
+{
+ struct task_struct *tsk = current;
+
+ memset(tsk->thread.debugreg, 0, sizeof(unsigned long)*8);
+
+ /*
+ * Forget coprocessor state..
+ */
+ clear_fpu(tsk);
+ tsk->used_math = 0;
+}
+
+void release_thread(struct task_struct *dead_task)
+{
+ if (dead_task->mm) {
+ void * ldt = dead_task->mm->context.segments;
+
+ // temporary debugging check
+ if (ldt) {
+ printk("WARNING: dead process %8s still has LDT? <%p>\n",
+ dead_task->comm, ldt);
+ BUG();
+ }
+ }
+}
+
+/*
+ * we do not have to muck with descriptors here, that is
+ * done in switch_mm() as needed.
+ */
+void copy_segments(struct task_struct *p, struct mm_struct *new_mm)
+{
+ struct mm_struct * old_mm;
+ void *old_ldt, *ldt;
+
+ ldt = NULL;
+ old_mm = current->mm;
+ if (old_mm && (old_ldt = old_mm->context.segments) != NULL) {
+ /*
+ * Completely new LDT, we initialize it from the parent:
+ */
+ ldt = vmalloc(LDT_ENTRIES*LDT_ENTRY_SIZE);
+ if ( ldt == NULL )
+ {
+ printk(KERN_WARNING "ldt allocation failed\n");
+ }
+ else
+ {
+ memcpy(ldt, old_ldt, LDT_ENTRIES*LDT_ENTRY_SIZE);
+ make_pages_readonly(ldt, (LDT_ENTRIES*LDT_ENTRY_SIZE)/PAGE_SIZE);
+ }
+ }
+ new_mm->context.segments = ldt;
+ new_mm->context.cpuvalid = ~0UL; /* valid on all CPU's - they can't have stale data */
+}
+
+/*
+ * Save a segment.
+ */
+#define savesegment(seg,value) \
+ asm volatile("movl %%" #seg ",%0":"=m" (*(int *)&(value)))
+
+int copy_thread(int nr, unsigned long clone_flags, unsigned long esp,
+ unsigned long unused,
+ struct task_struct * p, struct pt_regs * regs)
+{
+ struct pt_regs * childregs;
+ unsigned long eflags;
+
+ childregs = ((struct pt_regs *) (THREAD_SIZE + (unsigned long) p)) - 1;
+ struct_cpy(childregs, regs);
+ childregs->eax = 0;
+ childregs->esp = esp;
+
+ p->thread.esp = (unsigned long) childregs;
+ p->thread.esp0 = (unsigned long) (childregs+1);
+
+ p->thread.eip = (unsigned long) ret_from_fork;
+
+ savesegment(fs,p->thread.fs);
+ savesegment(gs,p->thread.gs);
+
+ unlazy_fpu(current);
+ struct_cpy(&p->thread.i387, ¤t->thread.i387);
+
+
+ __asm__ __volatile__ ( "pushfl; popl %0" : "=r" (eflags) : );
+ p->thread.io_pl = (eflags >> 12) & 3;
+
+ /* We're careful with hypercall privileges. Don't allow inheritance. */
+ p->thread.hypercall_pl = 1;
+
+ return 0;
+}
+
+/*
+ * fill in the user structure for a core dump..
+ */
+void dump_thread(struct pt_regs * regs, struct user * dump)
+{
+ int i;
+
+/* changed the size calculations - should hopefully work better. lbt */
+ dump->magic = CMAGIC;
+ dump->start_code = 0;
+ dump->start_stack = regs->esp & ~(PAGE_SIZE - 1);
+ dump->u_tsize = ((unsigned long) current->mm->end_code) >> PAGE_SHIFT;
+ dump->u_dsize = ((unsigned long) (current->mm->brk + (PAGE_SIZE-1))) >> PAGE_SHIFT;
+ dump->u_dsize -= dump->u_tsize;
+ dump->u_ssize = 0;
+ for (i = 0; i < 8; i++)
+ dump->u_debugreg[i] = current->thread.debugreg[i];
+
+ if (dump->start_stack < TASK_SIZE)
+ dump->u_ssize = ((unsigned long) (TASK_SIZE - dump->start_stack)) >> PAGE_SHIFT;
+
+ dump->regs.ebx = regs->ebx;
+ dump->regs.ecx = regs->ecx;
+ dump->regs.edx = regs->edx;
+ dump->regs.esi = regs->esi;
+ dump->regs.edi = regs->edi;
+ dump->regs.ebp = regs->ebp;
+ dump->regs.eax = regs->eax;
+ dump->regs.ds = regs->xds;
+ dump->regs.es = regs->xes;
+ savesegment(fs,dump->regs.fs);
+ savesegment(gs,dump->regs.gs);
+ dump->regs.orig_eax = regs->orig_eax;
+ dump->regs.eip = regs->eip;
+ dump->regs.cs = regs->xcs;
+ dump->regs.eflags = regs->eflags;
+ dump->regs.esp = regs->esp;
+ dump->regs.ss = regs->xss;
+
+ dump->u_fpvalid = dump_fpu (regs, &dump->i387);
+}
+
+/*
+ * switch_to(x,yn) should switch tasks from x to y.
+ *
+ * We fsave/fwait so that an exception goes off at the right time
+ * (as a call from the fsave or fwait in effect) rather than to
+ * the wrong process. Lazy FP saving no longer makes any sense
+ * with modern CPU's, and this simplifies a lot of things (SMP
+ * and UP become the same).
+ *
+ * NOTE! We used to use the x86 hardware context switching. The
+ * reason for not using it any more becomes apparent when you
+ * try to recover gracefully from saved state that is no longer
+ * valid (stale segment register values in particular). With the
+ * hardware task-switch, there is no way to fix up bad state in
+ * a reasonable manner.
+ *
+ * The fact that Intel documents the hardware task-switching to
+ * be slow is a fairly red herring - this code is not noticeably
+ * faster. However, there _is_ some room for improvement here,
+ * so the performance issues may eventually be a valid point.
+ * More important, however, is the fact that this allows us much
+ * more flexibility.
+ */
+void __switch_to(struct task_struct *prev_p, struct task_struct *next_p)
+{
+ struct thread_struct *prev = &prev_p->thread,
+ *next = &next_p->thread;
+
+ __cli();
+
+ MULTICALL_flush_page_update_queue();
+
+ /*
+ * This is basically 'unlazy_fpu', except that we queue a multicall to
+ * indicate FPU task switch, rather than synchronously trapping to Xen.
+ */
+ if ( prev_p->flags & PF_USEDFPU )
+ {
+ if ( cpu_has_fxsr )
+ asm volatile( "fxsave %0 ; fnclex"
+ : "=m" (prev_p->thread.i387.fxsave) );
+ else
+ asm volatile( "fnsave %0 ; fwait"
+ : "=m" (prev_p->thread.i387.fsave) );
+ prev_p->flags &= ~PF_USEDFPU;
+ queue_multicall0(__HYPERVISOR_fpu_taskswitch);
+ }
+
+ queue_multicall2(__HYPERVISOR_stack_switch, __KERNEL_DS, next->esp0);
+ /* Next call will silently fail if we are a non-privileged guest OS. */
+ queue_multicall2(__HYPERVISOR_set_priv_levels,
+ next->io_pl, next->hypercall_pl);
+
+ /* EXECUTE ALL TASK SWITCH XEN SYSCALLS AT THIS POINT. */
+ execute_multicall_list();
+ __sti();
+
+ /*
+ * Restore %fs and %gs.
+ */
+ loadsegment(fs, next->fs);
+ loadsegment(gs, next->gs);
+
+ /*
+ * Now maybe reload the debug registers
+ */
+ if ( next->debugreg[7] != 0 )
+ {
+ HYPERVISOR_set_debugreg(0, next->debugreg[0]);
+ HYPERVISOR_set_debugreg(1, next->debugreg[1]);
+ HYPERVISOR_set_debugreg(2, next->debugreg[2]);
+ HYPERVISOR_set_debugreg(3, next->debugreg[3]);
+ /* no 4 and 5 */
+ HYPERVISOR_set_debugreg(6, next->debugreg[6]);
+ HYPERVISOR_set_debugreg(7, next->debugreg[7]);
+ }
+}
+
+asmlinkage int sys_fork(struct pt_regs regs)
+{
+ return do_fork(SIGCHLD, regs.esp, ®s, 0);
+}
+
+asmlinkage int sys_clone(struct pt_regs regs)
+{
+ unsigned long clone_flags;
+ unsigned long newsp;
+
+ clone_flags = regs.ebx;
+ newsp = regs.ecx;
+ if (!newsp)
+ newsp = regs.esp;
+ return do_fork(clone_flags, newsp, ®s, 0);
+}
+
+/*
+ * This is trivial, and on the face of it looks like it
+ * could equally well be done in user mode.
+ *
+ * Not so, for quite unobvious reasons - register pressure.
+ * In user mode vfork() cannot have a stack frame, and if
+ * done by calling the "clone()" system call directly, you
+ * do not have enough call-clobbered registers to hold all
+ * the information you need.
+ */
+asmlinkage int sys_vfork(struct pt_regs regs)
+{
+ return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs.esp, ®s, 0);
+}
+
+/*
+ * sys_execve() executes a new program.
+ */
+asmlinkage int sys_execve(struct pt_regs regs)
+{
+ int error;
+ char * filename;
+
+ filename = getname((char *) regs.ebx);
+ error = PTR_ERR(filename);
+ if (IS_ERR(filename))
+ goto out;
+ error = do_execve(filename, (char **) regs.ecx, (char **) regs.edx, ®s);
+ if (error == 0)
+ current->ptrace &= ~PT_DTRACE;
+ putname(filename);
+ out:
+ return error;
+}
+
+/*
+ * These bracket the sleeping functions..
+ */
+extern void scheduling_functions_start_here(void);
+extern void scheduling_functions_end_here(void);
+#define first_sched ((unsigned long) scheduling_functions_start_here)
+#define last_sched ((unsigned long) scheduling_functions_end_here)
+
+unsigned long get_wchan(struct task_struct *p)
+{
+ unsigned long ebp, esp, eip;
+ unsigned long stack_page;
+ int count = 0;
+ if (!p || p == current || p->state == TASK_RUNNING)
+ return 0;
+ stack_page = (unsigned long)p;
+ esp = p->thread.esp;
+ if (!stack_page || esp < stack_page || esp > 8188+stack_page)
+ return 0;
+ /* include/asm-i386/system.h:switch_to() pushes ebp last. */
+ ebp = *(unsigned long *) esp;
+ do {
+ if (ebp < stack_page || ebp > 8184+stack_page)
+ return 0;
+ eip = *(unsigned long *) (ebp+4);
+ if (eip < first_sched || eip >= last_sched)
+ return eip;
+ ebp = *(unsigned long *) ebp;
+ } while (count++ < 16);
+ return 0;
+}
+#undef last_sched
+#undef first_sched
--- /dev/null
+/*
+ * linux/arch/i386/kernel/setup.c
+ *
+ * Copyright (C) 1995 Linus Torvalds
+ */
+
+/*
+ * This file handles the architecture-dependent parts of initialization
+ */
+
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/stddef.h>
+#include <linux/unistd.h>
+#include <linux/ptrace.h>
+#include <linux/slab.h>
+#include <linux/user.h>
+#include <linux/a.out.h>
+#include <linux/tty.h>
+#include <linux/ioport.h>
+#include <linux/delay.h>
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/apm_bios.h>
+#ifdef CONFIG_BLK_DEV_RAM
+#include <linux/blk.h>
+#endif
+#include <linux/highmem.h>
+#include <linux/bootmem.h>
+#include <linux/seq_file.h>
+#include <asm/processor.h>
+#include <linux/console.h>
+#include <asm/mtrr.h>
+#include <asm/uaccess.h>
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/smp.h>
+#include <asm/msr.h>
+#include <asm/desc.h>
+#include <asm/dma.h>
+#include <asm/mpspec.h>
+#include <asm/mmu_context.h>
+#include <asm/hypervisor.h>
+
+shared_info_t *HYPERVISOR_shared_info;
+
+unsigned long *phys_to_machine_mapping;
+
+/*
+ * Machine setup..
+ */
+
+char ignore_irq13; /* set if exception 16 works */
+struct cpuinfo_x86 boot_cpu_data = { 0, 0, 0, 0, -1, 1, 0, 0, -1 };
+
+unsigned long mmu_cr4_features;
+
+/*
+ * Bus types ..
+ */
+#ifdef CONFIG_EISA
+int EISA_bus;
+#endif
+int MCA_bus;
+
+/* for MCA, but anyone else can use it if they want */
+unsigned int machine_id;
+unsigned int machine_submodel_id;
+unsigned int BIOS_revision;
+unsigned int mca_pentium_flag;
+
+/* For PCI or other memory-mapped resources */
+unsigned long pci_mem_start = 0x10000000;
+
+/*
+ * Setup options
+ */
+struct drive_info_struct { char dummy[32]; } drive_info;
+struct screen_info screen_info;
+struct apm_info apm_info;
+struct sys_desc_table_struct {
+ unsigned short length;
+ unsigned char table[0];
+};
+
+unsigned char aux_device_present;
+
+extern int root_mountflags;
+extern char _text, _etext, _edata, _end;
+
+int enable_acpi_smp_table;
+
+/* Raw start-of-day parameters from the hypervisor. */
+union start_info_union start_info_union;
+
+#define COMMAND_LINE_SIZE 256
+static char command_line[COMMAND_LINE_SIZE];
+char saved_command_line[COMMAND_LINE_SIZE];
+
+static void __init parse_mem_cmdline (char ** cmdline_p)
+{
+ char c = ' ', *to = command_line, *from = saved_command_line;
+ int len = 0;
+
+ /* Save unparsed command line copy for /proc/cmdline */
+ memcpy(saved_command_line, start_info.cmd_line, COMMAND_LINE_SIZE);
+ saved_command_line[COMMAND_LINE_SIZE-1] = '\0';
+
+ for (;;) {
+ /*
+ * "mem=nopentium" disables the 4MB page tables.
+ * "mem=XXX[kKmM]" defines a memory region from HIGH_MEM
+ * to <mem>, overriding the bios size.
+ * "mem=XXX[KkmM]@XXX[KkmM]" defines a memory region from
+ * <start> to <start>+<mem>, overriding the bios size.
+ */
+ if (c == ' ' && !memcmp(from, "mem=", 4)) {
+ if (to != command_line)
+ to--;
+ if (!memcmp(from+4, "nopentium", 9)) {
+ from += 9+4;
+ } else if (!memcmp(from+4, "exactmap", 8)) {
+ from += 8+4;
+ } else {
+ (void)memparse(from+4, &from);
+ if (*from == '@')
+ (void)memparse(from+1, &from);
+ }
+ }
+
+ c = *(from++);
+ if (!c)
+ break;
+ if (COMMAND_LINE_SIZE <= ++len)
+ break;
+ *(to++) = c;
+ }
+ *to = '\0';
+ *cmdline_p = command_line;
+}
+
+void __init setup_arch(char **cmdline_p)
+{
+ unsigned long start_pfn, max_pfn, max_low_pfn;
+ unsigned long bootmap_size;
+ unsigned long i;
+
+ extern void hypervisor_callback(void);
+ extern void failsafe_callback(void);
+
+ extern unsigned long cpu0_pte_quicklist[];
+ extern unsigned long cpu0_pgd_quicklist[];
+
+ HYPERVISOR_set_callbacks(
+ __KERNEL_CS, (unsigned long)hypervisor_callback,
+ __KERNEL_CS, (unsigned long)failsafe_callback);
+
+ boot_cpu_data.pgd_quick = cpu0_pgd_quicklist;
+ boot_cpu_data.pte_quick = cpu0_pte_quicklist;
+
+ ROOT_DEV = MKDEV(RAMDISK_MAJOR,0);
+ memset(&drive_info, 0, sizeof(drive_info));
+ memset(&screen_info, 0, sizeof(screen_info));
+ // this is drawn from a dump from vgacon:startup in standard linux
+ screen_info.orig_video_mode = 3;
+ screen_info.orig_video_isVGA = 1;
+ screen_info.orig_video_lines = 25;
+ screen_info.orig_video_cols = 80;
+ screen_info.orig_video_ega_bx = 3;
+ screen_info.orig_video_points = 16;
+
+ memset(&apm_info.bios, 0, sizeof(apm_info.bios));
+ aux_device_present = 0;
+#ifdef CONFIG_BLK_DEV_RAM
+ rd_image_start = 0;
+ rd_prompt = 0;
+ rd_doload = 0;
+#endif
+
+ root_mountflags &= ~MS_RDONLY;
+ init_mm.start_code = (unsigned long) &_text;
+ init_mm.end_code = (unsigned long) &_etext;
+ init_mm.end_data = (unsigned long) &_edata;
+ init_mm.brk = (unsigned long) &_end;
+
+ parse_mem_cmdline(cmdline_p);
+
+#define PFN_UP(x) (((x) + PAGE_SIZE-1) >> PAGE_SHIFT)
+#define PFN_DOWN(x) ((x) >> PAGE_SHIFT)
+#define PFN_PHYS(x) ((x) << PAGE_SHIFT)
+
+/*
+ * 128MB for vmalloc and initrd
+ */
+#define VMALLOC_RESERVE (unsigned long)(128 << 20)
+#define MAXMEM (unsigned long)(HYPERVISOR_VIRT_START-PAGE_OFFSET-VMALLOC_RESERVE)
+#define MAXMEM_PFN PFN_DOWN(MAXMEM)
+#define MAX_NONPAE_PFN (1 << 20)
+
+ /*
+ * partially used pages are not usable - thus
+ * we are rounding upwards:
+ */
+#ifdef CONFIG_BLK_DEV_INITRD
+ if ( start_info.mod_start )
+ start_pfn = PFN_UP(__pa(start_info.mod_start + start_info.mod_len));
+ else
+#endif
+ start_pfn = PFN_UP(__pa(&_end));
+ max_pfn = start_info.nr_pages;
+
+ /*
+ * Determine low and high memory ranges:
+ */
+ max_low_pfn = max_pfn;
+ if (max_low_pfn > MAXMEM_PFN) {
+ max_low_pfn = MAXMEM_PFN;
+#ifndef CONFIG_HIGHMEM
+ /* Maximum memory usable is what is directly addressable */
+ printk(KERN_WARNING "Warning only %ldMB will be used.\n",
+ MAXMEM>>20);
+ if (max_pfn > MAX_NONPAE_PFN)
+ printk(KERN_WARNING "Use a PAE enabled kernel.\n");
+ else
+ printk(KERN_WARNING "Use a HIGHMEM enabled kernel.\n");
+#else /* !CONFIG_HIGHMEM */
+#ifndef CONFIG_X86_PAE
+ if (max_pfn > MAX_NONPAE_PFN) {
+ max_pfn = MAX_NONPAE_PFN;
+ printk(KERN_WARNING "Warning only 4GB will be used.\n");
+ printk(KERN_WARNING "Use a PAE enabled kernel.\n");
+ }
+#endif /* !CONFIG_X86_PAE */
+#endif /* !CONFIG_HIGHMEM */
+ }
+
+#ifdef CONFIG_HIGHMEM
+ highstart_pfn = highend_pfn = max_pfn;
+ if (max_pfn > MAXMEM_PFN) {
+ highstart_pfn = MAXMEM_PFN;
+ printk(KERN_NOTICE "%ldMB HIGHMEM available.\n",
+ pages_to_mb(highend_pfn - highstart_pfn));
+ }
+#endif
+
+ /*
+ * Initialize the boot-time allocator, and free up all RAM.
+ * Then reserve space for OS image, and the bootmem bitmap.
+ */
+ bootmap_size = init_bootmem(start_pfn, max_low_pfn);
+ free_bootmem(0, PFN_PHYS(max_low_pfn));
+ reserve_bootmem(0, PFN_PHYS(start_pfn) + bootmap_size + PAGE_SIZE-1);
+
+ /* Now reserve space for the hypervisor-provided page tables. */
+ {
+ unsigned long *pgd = (unsigned long *)start_info.pt_base;
+ unsigned long pte;
+ int i;
+ reserve_bootmem(__pa(pgd), PAGE_SIZE);
+ for ( i = 0; i < (HYPERVISOR_VIRT_START>>22); i++ )
+ {
+ unsigned long pgde = *pgd++;
+ if ( !(pgde & 1) ) continue;
+ pte = machine_to_phys(pgde & PAGE_MASK);
+ reserve_bootmem(pte, PAGE_SIZE);
+ }
+ }
+ cur_pgd = init_mm.pgd = (pgd_t *)start_info.pt_base;
+
+ /* Now initialise the physical->machine mapping table. */
+ phys_to_machine_mapping = alloc_bootmem(max_pfn * sizeof(unsigned long));
+ for ( i = 0; i < max_pfn; i++ )
+ {
+ unsigned long pgde, *ppte;
+ unsigned long pfn = i + (PAGE_OFFSET >> PAGE_SHIFT);
+ pgde = *((unsigned long *)start_info.pt_base + (pfn >> 10));
+ ppte = (unsigned long *)machine_to_phys(pgde & PAGE_MASK) + (pfn&1023);
+ phys_to_machine_mapping[i] =
+ (*(unsigned long *)__va(ppte)) >> PAGE_SHIFT;
+ }
+
+#ifdef CONFIG_BLK_DEV_INITRD
+ if (start_info.mod_start) {
+ if ((__pa(start_info.mod_start) + start_info.mod_len) <=
+ (max_low_pfn << PAGE_SHIFT)) {
+ initrd_start = start_info.mod_start;
+ initrd_end = initrd_start + start_info.mod_len;
+ initrd_below_start_ok = 1;
+ }
+ else {
+ printk(KERN_ERR "initrd extends beyond end of memory "
+ "(0x%08lx > 0x%08lx)\ndisabling initrd\n",
+ __pa(start_info.mod_start) + start_info.mod_len,
+ max_low_pfn << PAGE_SHIFT);
+ initrd_start = 0;
+ }
+ }
+#endif
+
+ paging_init();
+
+ current->thread.hypercall_pl = 1;
+ if ( start_info.flags & SIF_PRIVILEGED ) {
+ current->thread.io_pl = 1;
+ /* We are privileged guest os - should have IO privileges. */
+ if( HYPERVISOR_set_priv_levels(1, 1) )
+ panic("Unable to obtain IOPL, despite being SIF_PRIVILEGED");
+ }
+
+ if(start_info.flags & SIF_CONSOLE)
+ {
+ if( !(start_info.flags & SIF_PRIVILEGED) )
+ panic("Xen granted us console access but not privileged status");
+
+#ifdef CONFIG_VT
+#if defined(CONFIG_VGA_CONSOLE)
+ conswitchp = &vga_con;
+#elif defined(CONFIG_DUMMY_CONSOLE)
+ conswitchp = &dummy_con;
+#endif
+#endif
+ }
+}
+
+static int cachesize_override __initdata = -1;
+static int __init cachesize_setup(char *str)
+{
+ get_option (&str, &cachesize_override);
+ return 1;
+}
+__setup("cachesize=", cachesize_setup);
+
+
+static int __init get_model_name(struct cpuinfo_x86 *c)
+{
+ unsigned int *v;
+ char *p, *q;
+
+ if (cpuid_eax(0x80000000) < 0x80000004)
+ return 0;
+
+ v = (unsigned int *) c->x86_model_id;
+ cpuid(0x80000002, &v[0], &v[1], &v[2], &v[3]);
+ cpuid(0x80000003, &v[4], &v[5], &v[6], &v[7]);
+ cpuid(0x80000004, &v[8], &v[9], &v[10], &v[11]);
+ c->x86_model_id[48] = 0;
+
+ /* Intel chips right-justify this string for some dumb reason;
+ undo that brain damage */
+ p = q = &c->x86_model_id[0];
+ while ( *p == ' ' )
+ p++;
+ if ( p != q ) {
+ while ( *p )
+ *q++ = *p++;
+ while ( q <= &c->x86_model_id[48] )
+ *q++ = '\0'; /* Zero-pad the rest */
+ }
+
+ return 1;
+}
+
+
+static void __init display_cacheinfo(struct cpuinfo_x86 *c)
+{
+ unsigned int n, dummy, ecx, edx, l2size;
+
+ n = cpuid_eax(0x80000000);
+
+ if (n >= 0x80000005) {
+ cpuid(0x80000005, &dummy, &dummy, &ecx, &edx);
+ printk(KERN_INFO "CPU: L1 I Cache: %dK (%d bytes/line), D cache %dK (%d bytes/line)\n",
+ edx>>24, edx&0xFF, ecx>>24, ecx&0xFF);
+ c->x86_cache_size=(ecx>>24)+(edx>>24);
+ }
+
+ if (n < 0x80000006) /* Some chips just has a large L1. */
+ return;
+
+ ecx = cpuid_ecx(0x80000006);
+ l2size = ecx >> 16;
+
+ /* AMD errata T13 (order #21922) */
+ if ((c->x86_vendor == X86_VENDOR_AMD) && (c->x86 == 6)) {
+ if (c->x86_model == 3 && c->x86_mask == 0) /* Duron Rev A0 */
+ l2size = 64;
+ if (c->x86_model == 4 &&
+ (c->x86_mask==0 || c->x86_mask==1)) /* Tbird rev A1/A2 */
+ l2size = 256;
+ }
+
+ /* Intel PIII Tualatin. This comes in two flavours.
+ * One has 256kb of cache, the other 512. We have no way
+ * to determine which, so we use a boottime override
+ * for the 512kb model, and assume 256 otherwise.
+ */
+ if ((c->x86_vendor == X86_VENDOR_INTEL) && (c->x86 == 6) &&
+ (c->x86_model == 11) && (l2size == 0))
+ l2size = 256;
+
+ if (c->x86_vendor == X86_VENDOR_CENTAUR) {
+ /* VIA C3 CPUs (670-68F) need further shifting. */
+ if ((c->x86 == 6) &&
+ ((c->x86_model == 7) || (c->x86_model == 8))) {
+ l2size >>= 8;
+ }
+
+ /* VIA also screwed up Nehemiah stepping 1, and made
+ it return '65KB' instead of '64KB'
+ - Note, it seems this may only be in engineering samples. */
+ if ((c->x86==6) && (c->x86_model==9) &&
+ (c->x86_mask==1) && (l2size==65))
+ l2size -= 1;
+ }
+
+ /* Allow user to override all this if necessary. */
+ if (cachesize_override != -1)
+ l2size = cachesize_override;
+
+ if ( l2size == 0 )
+ return; /* Again, no L2 cache is possible */
+
+ c->x86_cache_size = l2size;
+
+ printk(KERN_INFO "CPU: L2 Cache: %dK (%d bytes/line)\n",
+ l2size, ecx & 0xFF);
+}
+
+
+static int __init init_amd(struct cpuinfo_x86 *c)
+{
+ int r;
+
+ /* Bit 31 in normal CPUID used for nonstandard 3DNow ID;
+ 3DNow is IDd by bit 31 in extended CPUID (1*32+31) anyway */
+ clear_bit(0*32+31, &c->x86_capability);
+
+ r = get_model_name(c);
+
+ switch(c->x86)
+ {
+ case 6: /* An Athlon/Duron. We can trust the BIOS probably */
+ break;
+ default:
+ panic("Unsupported AMD processor\n");
+ }
+
+ display_cacheinfo(c);
+ return r;
+}
+
+
+static void __init init_intel(struct cpuinfo_x86 *c)
+{
+ char *p = NULL;
+ unsigned int l1i = 0, l1d = 0, l2 = 0, l3 = 0; /* Cache sizes */
+
+ if (c->cpuid_level > 1) {
+ /* supports eax=2 call */
+ int i, j, n;
+ int regs[4];
+ unsigned char *dp = (unsigned char *)regs;
+
+ /* Number of times to iterate */
+ n = cpuid_eax(2) & 0xFF;
+
+ for ( i = 0 ; i < n ; i++ ) {
+ cpuid(2, ®s[0], ®s[1], ®s[2], ®s[3]);
+
+ /* If bit 31 is set, this is an unknown format */
+ for ( j = 0 ; j < 3 ; j++ ) {
+ if ( regs[j] < 0 ) regs[j] = 0;
+ }
+
+ /* Byte 0 is level count, not a descriptor */
+ for ( j = 1 ; j < 16 ; j++ ) {
+ unsigned char des = dp[j];
+ unsigned char dl, dh;
+ unsigned int cs;
+
+ dh = des >> 4;
+ dl = des & 0x0F;
+
+ /* Black magic... */
+
+ switch ( dh )
+ {
+ case 0:
+ switch ( dl ) {
+ case 6:
+ /* L1 I cache */
+ l1i += 8;
+ break;
+ case 8:
+ /* L1 I cache */
+ l1i += 16;
+ break;
+ case 10:
+ /* L1 D cache */
+ l1d += 8;
+ break;
+ case 12:
+ /* L1 D cache */
+ l1d += 16;
+ break;
+ default:;
+ /* TLB, or unknown */
+ }
+ break;
+ case 2:
+ if ( dl ) {
+ /* L3 cache */
+ cs = (dl-1) << 9;
+ l3 += cs;
+ }
+ break;
+ case 4:
+ if ( c->x86 > 6 && dl ) {
+ /* P4 family */
+ /* L3 cache */
+ cs = 128 << (dl-1);
+ l3 += cs;
+ break;
+ }
+ /* else same as 8 - fall through */
+ case 8:
+ if ( dl ) {
+ /* L2 cache */
+ cs = 128 << (dl-1);
+ l2 += cs;
+ }
+ break;
+ case 6:
+ if (dl > 5) {
+ /* L1 D cache */
+ cs = 8<<(dl-6);
+ l1d += cs;
+ }
+ break;
+ case 7:
+ if ( dl >= 8 )
+ {
+ /* L2 cache */
+ cs = 64<<(dl-8);
+ l2 += cs;
+ } else {
+ /* L0 I cache, count as L1 */
+ cs = dl ? (16 << (dl-1)) : 12;
+ l1i += cs;
+ }
+ break;
+ default:
+ /* TLB, or something else we don't know about */
+ break;
+ }
+ }
+ }
+ if ( l1i || l1d )
+ printk(KERN_INFO "CPU: L1 I cache: %dK, L1 D cache: %dK\n",
+ l1i, l1d);
+ if ( l2 )
+ printk(KERN_INFO "CPU: L2 cache: %dK\n", l2);
+ if ( l3 )
+ printk(KERN_INFO "CPU: L3 cache: %dK\n", l3);
+
+ /*
+ * This assumes the L3 cache is shared; it typically lives in
+ * the northbridge. The L1 caches are included by the L2
+ * cache, and so should not be included for the purpose of
+ * SMP switching weights.
+ */
+ c->x86_cache_size = l2 ? l2 : (l1i+l1d);
+ }
+
+ /* SEP CPUID bug: Pentium Pro reports SEP but doesn't have it */
+ if ( c->x86 == 6 && c->x86_model < 3 && c->x86_mask < 3 )
+ clear_bit(X86_FEATURE_SEP, &c->x86_capability);
+
+ /* Names for the Pentium II/Celeron processors
+ detectable only by also checking the cache size.
+ Dixon is NOT a Celeron. */
+ if (c->x86 == 6) {
+ switch (c->x86_model) {
+ case 5:
+ if (l2 == 0)
+ p = "Celeron (Covington)";
+ if (l2 == 256)
+ p = "Mobile Pentium II (Dixon)";
+ break;
+
+ case 6:
+ if (l2 == 128)
+ p = "Celeron (Mendocino)";
+ break;
+
+ case 8:
+ if (l2 == 128)
+ p = "Celeron (Coppermine)";
+ break;
+ }
+ }
+
+ if ( p )
+ strcpy(c->x86_model_id, p);
+}
+
+void __init get_cpu_vendor(struct cpuinfo_x86 *c)
+{
+ char *v = c->x86_vendor_id;
+
+ if (!strcmp(v, "GenuineIntel"))
+ c->x86_vendor = X86_VENDOR_INTEL;
+ else if (!strcmp(v, "AuthenticAMD"))
+ c->x86_vendor = X86_VENDOR_AMD;
+ else
+ c->x86_vendor = X86_VENDOR_UNKNOWN;
+}
+
+struct cpu_model_info {
+ int vendor;
+ int family;
+ char *model_names[16];
+};
+
+/* Naming convention should be: <Name> [(<Codename>)] */
+/* This table only is used unless init_<vendor>() below doesn't set it; */
+/* in particular, if CPUID levels 0x80000002..4 are supported, this isn't used */
+static struct cpu_model_info cpu_models[] __initdata = {
+ { X86_VENDOR_INTEL, 6,
+ { "Pentium Pro A-step", "Pentium Pro", NULL, "Pentium II (Klamath)",
+ NULL, "Pentium II (Deschutes)", "Mobile Pentium II",
+ "Pentium III (Katmai)", "Pentium III (Coppermine)", NULL,
+ "Pentium III (Cascades)", NULL, NULL, NULL, NULL }},
+ { X86_VENDOR_AMD, 6, /* Is this this really necessary?? */
+ { "Athlon", "Athlon",
+ "Athlon", NULL, "Athlon", NULL,
+ NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL }}
+};
+
+/* Look up CPU names by table lookup. */
+static char __init *table_lookup_model(struct cpuinfo_x86 *c)
+{
+ struct cpu_model_info *info = cpu_models;
+ int i;
+
+ if ( c->x86_model >= 16 )
+ return NULL; /* Range check */
+
+ for ( i = 0 ; i < sizeof(cpu_models)/sizeof(struct cpu_model_info) ; i++ ) {
+ if ( info->vendor == c->x86_vendor &&
+ info->family == c->x86 ) {
+ return info->model_names[c->x86_model];
+ }
+ info++;
+ }
+ return NULL; /* Not found */
+}
+
+
+
+/* Standard macro to see if a specific flag is changeable */
+static inline int flag_is_changeable_p(u32 flag)
+{
+ u32 f1, f2;
+
+ asm("pushfl\n\t"
+ "pushfl\n\t"
+ "popl %0\n\t"
+ "movl %0,%1\n\t"
+ "xorl %2,%0\n\t"
+ "pushl %0\n\t"
+ "popfl\n\t"
+ "pushfl\n\t"
+ "popl %0\n\t"
+ "popfl\n\t"
+ : "=&r" (f1), "=&r" (f2)
+ : "ir" (flag));
+
+ return ((f1^f2) & flag) != 0;
+}
+
+
+/* Probe for the CPUID instruction */
+static int __init have_cpuid_p(void)
+{
+ return flag_is_changeable_p(X86_EFLAGS_ID);
+}
+
+
+
+/*
+ * This does the hard work of actually picking apart the CPU stuff...
+ */
+void __init identify_cpu(struct cpuinfo_x86 *c)
+{
+ int junk, i;
+ u32 xlvl, tfms;
+
+ c->loops_per_jiffy = loops_per_jiffy;
+ c->x86_cache_size = -1;
+ c->x86_vendor = X86_VENDOR_UNKNOWN;
+ c->cpuid_level = -1; /* CPUID not detected */
+ c->x86_model = c->x86_mask = 0; /* So far unknown... */
+ c->x86_vendor_id[0] = '\0'; /* Unset */
+ c->x86_model_id[0] = '\0'; /* Unset */
+ memset(&c->x86_capability, 0, sizeof c->x86_capability);
+ c->hard_math = 1;
+
+ if ( !have_cpuid_p() ) {
+ panic("Processor must support CPUID\n");
+ } else {
+ /* CPU does have CPUID */
+
+ /* Get vendor name */
+ cpuid(0x00000000, &c->cpuid_level,
+ (int *)&c->x86_vendor_id[0],
+ (int *)&c->x86_vendor_id[8],
+ (int *)&c->x86_vendor_id[4]);
+
+ get_cpu_vendor(c);
+ /* Initialize the standard set of capabilities */
+ /* Note that the vendor-specific code below might override */
+
+ /* Intel-defined flags: level 0x00000001 */
+ if ( c->cpuid_level >= 0x00000001 ) {
+ cpuid(0x00000001, &tfms, &junk, &junk,
+ &c->x86_capability[0]);
+ c->x86 = (tfms >> 8) & 15;
+ c->x86_model = (tfms >> 4) & 15;
+ c->x86_mask = tfms & 15;
+ } else {
+ /* Have CPUID level 0 only - unheard of */
+ c->x86 = 4;
+ }
+
+ /* AMD-defined flags: level 0x80000001 */
+ xlvl = cpuid_eax(0x80000000);
+ if ( (xlvl & 0xffff0000) == 0x80000000 ) {
+ if ( xlvl >= 0x80000001 )
+ c->x86_capability[1] = cpuid_edx(0x80000001);
+ if ( xlvl >= 0x80000004 )
+ get_model_name(c); /* Default name */
+ }
+
+ /* Transmeta-defined flags: level 0x80860001 */
+ xlvl = cpuid_eax(0x80860000);
+ if ( (xlvl & 0xffff0000) == 0x80860000 ) {
+ if ( xlvl >= 0x80860001 )
+ c->x86_capability[2] = cpuid_edx(0x80860001);
+ }
+ }
+
+ printk(KERN_DEBUG "CPU: Before vendor init, caps: %08x %08x %08x, vendor = %d\n",
+ c->x86_capability[0],
+ c->x86_capability[1],
+ c->x86_capability[2],
+ c->x86_vendor);
+
+ /*
+ * Vendor-specific initialization. In this section we
+ * canonicalize the feature flags, meaning if there are
+ * features a certain CPU supports which CPUID doesn't
+ * tell us, CPUID claiming incorrect flags, or other bugs,
+ * we handle them here.
+ *
+ * At the end of this section, c->x86_capability better
+ * indicate the features this CPU genuinely supports!
+ */
+ switch ( c->x86_vendor ) {
+ case X86_VENDOR_AMD:
+ init_amd(c);
+ break;
+
+ case X86_VENDOR_INTEL:
+ init_intel(c);
+ break;
+
+ default:
+ panic("Unsupported CPU vendor\n");
+ }
+
+ printk(KERN_DEBUG "CPU: After vendor init, caps: %08x %08x %08x %08x\n",
+ c->x86_capability[0],
+ c->x86_capability[1],
+ c->x86_capability[2],
+ c->x86_capability[3]);
+
+
+ /* If the model name is still unset, do table lookup. */
+ if ( !c->x86_model_id[0] ) {
+ char *p;
+ p = table_lookup_model(c);
+ if ( p )
+ strcpy(c->x86_model_id, p);
+ else
+ /* Last resort... */
+ sprintf(c->x86_model_id, "%02x/%02x",
+ c->x86_vendor, c->x86_model);
+ }
+
+ /* Now the feature flags better reflect actual CPU features! */
+
+ printk(KERN_DEBUG "CPU: After generic, caps: %08x %08x %08x %08x\n",
+ c->x86_capability[0],
+ c->x86_capability[1],
+ c->x86_capability[2],
+ c->x86_capability[3]);
+
+ /*
+ * On SMP, boot_cpu_data holds the common feature set between
+ * all CPUs; so make sure that we indicate which features are
+ * common between the CPUs. The first time this routine gets
+ * executed, c == &boot_cpu_data.
+ */
+ if ( c != &boot_cpu_data ) {
+ /* AND the already accumulated flags with these */
+ for ( i = 0 ; i < NCAPINTS ; i++ )
+ boot_cpu_data.x86_capability[i] &= c->x86_capability[i];
+ }
+
+ printk(KERN_DEBUG "CPU: Common caps: %08x %08x %08x %08x\n",
+ boot_cpu_data.x86_capability[0],
+ boot_cpu_data.x86_capability[1],
+ boot_cpu_data.x86_capability[2],
+ boot_cpu_data.x86_capability[3]);
+}
+
+
+/* These need to match <asm/processor.h> */
+static char *cpu_vendor_names[] __initdata = {
+ "Intel", "Cyrix", "AMD", "UMC", "NexGen", "Centaur", "Rise", "Transmeta" };
+
+
+void __init print_cpu_info(struct cpuinfo_x86 *c)
+{
+ char *vendor = NULL;
+
+ if (c->x86_vendor < sizeof(cpu_vendor_names)/sizeof(char *))
+ vendor = cpu_vendor_names[c->x86_vendor];
+ else if (c->cpuid_level >= 0)
+ vendor = c->x86_vendor_id;
+
+ if (vendor && strncmp(c->x86_model_id, vendor, strlen(vendor)))
+ printk("%s ", vendor);
+
+ if (!c->x86_model_id[0])
+ printk("%d86", c->x86);
+ else
+ printk("%s", c->x86_model_id);
+
+ if (c->x86_mask || c->cpuid_level >= 0)
+ printk(" stepping %02x\n", c->x86_mask);
+ else
+ printk("\n");
+}
+
+/*
+ * Get CPU information for use by the procfs.
+ */
+static int show_cpuinfo(struct seq_file *m, void *v)
+{
+ /*
+ * These flag bits must match the definitions in <asm/cpufeature.h>.
+ * NULL means this bit is undefined or reserved; either way it doesn't
+ * have meaning as far as Linux is concerned. Note that it's important
+ * to realize there is a difference between this table and CPUID -- if
+ * applications want to get the raw CPUID data, they should access
+ * /dev/cpu/<cpu_nr>/cpuid instead.
+ */
+ static char *x86_cap_flags[] = {
+ /* Intel-defined */
+ "fpu", "vme", "de", "pse", "tsc", "msr", "pae", "mce",
+ "cx8", "apic", NULL, "sep", "mtrr", "pge", "mca", "cmov",
+ "pat", "pse36", "pn", "clflush", NULL, "dts", "acpi", "mmx",
+ "fxsr", "sse", "sse2", "ss", NULL, "tm", "ia64", NULL,
+
+ /* AMD-defined */
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, "syscall", NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, "mmxext", NULL,
+ NULL, NULL, NULL, NULL, NULL, "lm", "3dnowext", "3dnow",
+
+ /* Transmeta-defined */
+ "recovery", "longrun", NULL, "lrti", NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+
+ /* Other (Linux-defined) */
+ "cxmmx", "k6_mtrr", "cyrix_arr", "centaur_mcr", NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ };
+ struct cpuinfo_x86 *c = v;
+ int i, n = c - cpu_data;
+ int fpu_exception;
+
+#ifdef CONFIG_SMP
+ if (!(cpu_online_map & (1<<n)))
+ return 0;
+#endif
+ seq_printf(m, "processor\t: %d\n"
+ "vendor_id\t: %s\n"
+ "cpu family\t: %d\n"
+ "model\t\t: %d\n"
+ "model name\t: %s\n",
+ n,
+ c->x86_vendor_id[0] ? c->x86_vendor_id : "unknown",
+ c->x86,
+ c->x86_model,
+ c->x86_model_id[0] ? c->x86_model_id : "unknown");
+
+ if (c->x86_mask || c->cpuid_level >= 0)
+ seq_printf(m, "stepping\t: %d\n", c->x86_mask);
+ else
+ seq_printf(m, "stepping\t: unknown\n");
+
+ if ( test_bit(X86_FEATURE_TSC, &c->x86_capability) ) {
+ seq_printf(m, "cpu MHz\t\t: %lu.%03lu\n",
+ cpu_khz / 1000, (cpu_khz % 1000));
+ }
+
+ /* Cache size */
+ if (c->x86_cache_size >= 0)
+ seq_printf(m, "cache size\t: %d KB\n", c->x86_cache_size);
+
+ /* We use exception 16 if we have hardware math and we've either seen it or the CPU claims it is internal */
+ fpu_exception = c->hard_math && (ignore_irq13 || cpu_has_fpu);
+ seq_printf(m, "fdiv_bug\t: %s\n"
+ "hlt_bug\t\t: %s\n"
+ "f00f_bug\t: %s\n"
+ "coma_bug\t: %s\n"
+ "fpu\t\t: %s\n"
+ "fpu_exception\t: %s\n"
+ "cpuid level\t: %d\n"
+ "wp\t\t: %s\n"
+ "flags\t\t:",
+ c->fdiv_bug ? "yes" : "no",
+ c->hlt_works_ok ? "no" : "yes",
+ c->f00f_bug ? "yes" : "no",
+ c->coma_bug ? "yes" : "no",
+ c->hard_math ? "yes" : "no",
+ fpu_exception ? "yes" : "no",
+ c->cpuid_level,
+ c->wp_works_ok ? "yes" : "no");
+
+ for ( i = 0 ; i < 32*NCAPINTS ; i++ )
+ if ( test_bit(i, &c->x86_capability) &&
+ x86_cap_flags[i] != NULL )
+ seq_printf(m, " %s", x86_cap_flags[i]);
+
+ seq_printf(m, "\nbogomips\t: %lu.%02lu\n\n",
+ c->loops_per_jiffy/(500000/HZ),
+ (c->loops_per_jiffy/(5000/HZ)) % 100);
+ return 0;
+}
+
+static void *c_start(struct seq_file *m, loff_t *pos)
+{
+ return *pos < NR_CPUS ? cpu_data + *pos : NULL;
+}
+static void *c_next(struct seq_file *m, void *v, loff_t *pos)
+{
+ ++*pos;
+ return c_start(m, pos);
+}
+static void c_stop(struct seq_file *m, void *v)
+{
+}
+struct seq_operations cpuinfo_op = {
+ start: c_start,
+ next: c_next,
+ stop: c_stop,
+ show: show_cpuinfo,
+};
+
+unsigned long cpu_initialized __initdata = 0;
+
+/*
+ * cpu_init() initializes state that is per-CPU. Some data is already
+ * initialized (naturally) in the bootstrap process, such as the GDT
+ * and IDT. We reload them nevertheless, this function acts as a
+ * 'CPU state barrier', nothing should get across.
+ */
+void __init cpu_init (void)
+{
+ int nr = smp_processor_id();
+
+ if (test_and_set_bit(nr, &cpu_initialized)) {
+ printk(KERN_WARNING "CPU#%d already initialized!\n", nr);
+ for (;;) __sti();
+ }
+ printk(KERN_INFO "Initializing CPU#%d\n", nr);
+
+ /*
+ * set up and load the per-CPU TSS and LDT
+ */
+ atomic_inc(&init_mm.mm_count);
+ current->active_mm = &init_mm;
+ if(current->mm)
+ BUG();
+ enter_lazy_tlb(&init_mm, current, nr);
+
+ HYPERVISOR_stack_switch(__KERNEL_DS, current->thread.esp0);
+
+ load_LDT(&init_mm);
+ flush_page_update_queue();
+
+ /* Force FPU initialization. */
+ current->flags &= ~PF_USEDFPU;
+ current->used_math = 0;
+ stts();
+}
+
+
+/******************************************************************************
+ * Time-to-die callback handling.
+ */
+
+static void time_to_die(int irq, void *unused, struct pt_regs *regs)
+{
+ extern void ctrl_alt_del(void);
+ ctrl_alt_del();
+}
+
+static int __init setup_death_event(void)
+{
+ (void)request_irq(_EVENT_DIE, time_to_die, 0, "die", NULL);
+ return 0;
+}
+
+__initcall(setup_death_event);
--- /dev/null
+/*
+ * linux/arch/i386/kernel/signal.c
+ *
+ * Copyright (C) 1991, 1992 Linus Torvalds
+ *
+ * 1997-11-28 Modified for POSIX.1b signals by Richard Henderson
+ * 2000-06-20 Pentium III FXSR, SSE support by Gareth Hughes
+ */
+
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
+#include <linux/kernel.h>
+#include <linux/signal.h>
+#include <linux/errno.h>
+#include <linux/wait.h>
+#include <linux/ptrace.h>
+#include <linux/unistd.h>
+#include <linux/stddef.h>
+#include <linux/tty.h>
+#include <linux/personality.h>
+#include <asm/ucontext.h>
+#include <asm/uaccess.h>
+#include <asm/i387.h>
+
+#define DEBUG_SIG 0
+
+#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
+
+int FASTCALL(do_signal(struct pt_regs *regs, sigset_t *oldset));
+
+int copy_siginfo_to_user(siginfo_t *to, siginfo_t *from)
+{
+ if (!access_ok (VERIFY_WRITE, to, sizeof(siginfo_t)))
+ return -EFAULT;
+ if (from->si_code < 0)
+ return __copy_to_user(to, from, sizeof(siginfo_t));
+ else {
+ int err;
+
+ /* If you change siginfo_t structure, please be sure
+ this code is fixed accordingly.
+ It should never copy any pad contained in the structure
+ to avoid security leaks, but must copy the generic
+ 3 ints plus the relevant union member. */
+ err = __put_user(from->si_signo, &to->si_signo);
+ err |= __put_user(from->si_errno, &to->si_errno);
+ err |= __put_user((short)from->si_code, &to->si_code);
+ /* First 32bits of unions are always present. */
+ err |= __put_user(from->si_pid, &to->si_pid);
+ switch (from->si_code >> 16) {
+ case __SI_FAULT >> 16:
+ break;
+ case __SI_CHLD >> 16:
+ err |= __put_user(from->si_utime, &to->si_utime);
+ err |= __put_user(from->si_stime, &to->si_stime);
+ err |= __put_user(from->si_status, &to->si_status);
+ default:
+ err |= __put_user(from->si_uid, &to->si_uid);
+ break;
+ /* case __SI_RT: This is not generated by the kernel as of now. */
+ }
+ return err;
+ }
+}
+
+/*
+ * Atomically swap in the new signal mask, and wait for a signal.
+ */
+asmlinkage int
+sys_sigsuspend(int history0, int history1, old_sigset_t mask)
+{
+ struct pt_regs * regs = (struct pt_regs *) &history0;
+ sigset_t saveset;
+
+ mask &= _BLOCKABLE;
+ spin_lock_irq(¤t->sigmask_lock);
+ saveset = current->blocked;
+ siginitset(¤t->blocked, mask);
+ recalc_sigpending(current);
+ spin_unlock_irq(¤t->sigmask_lock);
+
+ regs->eax = -EINTR;
+ while (1) {
+ current->state = TASK_INTERRUPTIBLE;
+ schedule();
+ if (do_signal(regs, &saveset))
+ return -EINTR;
+ }
+}
+
+asmlinkage int
+sys_rt_sigsuspend(sigset_t *unewset, size_t sigsetsize)
+{
+ struct pt_regs * regs = (struct pt_regs *) &unewset;
+ sigset_t saveset, newset;
+
+ /* XXX: Don't preclude handling different sized sigset_t's. */
+ if (sigsetsize != sizeof(sigset_t))
+ return -EINVAL;
+
+ if (copy_from_user(&newset, unewset, sizeof(newset)))
+ return -EFAULT;
+ sigdelsetmask(&newset, ~_BLOCKABLE);
+
+ spin_lock_irq(¤t->sigmask_lock);
+ saveset = current->blocked;
+ current->blocked = newset;
+ recalc_sigpending(current);
+ spin_unlock_irq(¤t->sigmask_lock);
+
+ regs->eax = -EINTR;
+ while (1) {
+ current->state = TASK_INTERRUPTIBLE;
+ schedule();
+ if (do_signal(regs, &saveset))
+ return -EINTR;
+ }
+}
+
+asmlinkage int
+sys_sigaction(int sig, const struct old_sigaction *act,
+ struct old_sigaction *oact)
+{
+ struct k_sigaction new_ka, old_ka;
+ int ret;
+
+ if (act) {
+ old_sigset_t mask;
+ if (verify_area(VERIFY_READ, act, sizeof(*act)) ||
+ __get_user(new_ka.sa.sa_handler, &act->sa_handler) ||
+ __get_user(new_ka.sa.sa_restorer, &act->sa_restorer))
+ return -EFAULT;
+ __get_user(new_ka.sa.sa_flags, &act->sa_flags);
+ __get_user(mask, &act->sa_mask);
+ siginitset(&new_ka.sa.sa_mask, mask);
+ }
+
+ ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
+
+ if (!ret && oact) {
+ if (verify_area(VERIFY_WRITE, oact, sizeof(*oact)) ||
+ __put_user(old_ka.sa.sa_handler, &oact->sa_handler) ||
+ __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer))
+ return -EFAULT;
+ __put_user(old_ka.sa.sa_flags, &oact->sa_flags);
+ __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask);
+ }
+
+ return ret;
+}
+
+asmlinkage int
+sys_sigaltstack(const stack_t *uss, stack_t *uoss)
+{
+ struct pt_regs *regs = (struct pt_regs *) &uss;
+ return do_sigaltstack(uss, uoss, regs->esp);
+}
+
+
+/*
+ * Do a signal return; undo the signal stack.
+ */
+
+struct sigframe
+{
+ char *pretcode;
+ int sig;
+ struct sigcontext sc;
+ struct _fpstate fpstate;
+ unsigned long extramask[_NSIG_WORDS-1];
+ char retcode[8];
+};
+
+struct rt_sigframe
+{
+ char *pretcode;
+ int sig;
+ struct siginfo *pinfo;
+ void *puc;
+ struct siginfo info;
+ struct ucontext uc;
+ struct _fpstate fpstate;
+ char retcode[8];
+};
+
+static int
+restore_sigcontext(struct pt_regs *regs, struct sigcontext *sc, int *peax)
+{
+ unsigned int err = 0;
+
+#define COPY(x) err |= __get_user(regs->x, &sc->x)
+
+#define COPY_SEG(seg) \
+ { unsigned short tmp; \
+ err |= __get_user(tmp, &sc->seg); \
+ regs->x##seg = tmp; }
+
+#define COPY_SEG_STRICT(seg) \
+ { unsigned short tmp; \
+ err |= __get_user(tmp, &sc->seg); \
+ regs->x##seg = tmp|3; }
+
+#define GET_SEG(seg) \
+ { unsigned short tmp; \
+ err |= __get_user(tmp, &sc->seg); \
+ loadsegment(seg,tmp); }
+
+ GET_SEG(gs);
+ GET_SEG(fs);
+ COPY_SEG(es);
+ COPY_SEG(ds);
+ COPY(edi);
+ COPY(esi);
+ COPY(ebp);
+ COPY(esp);
+ COPY(ebx);
+ COPY(edx);
+ COPY(ecx);
+ COPY(eip);
+ COPY_SEG_STRICT(cs);
+ COPY_SEG_STRICT(ss);
+
+ {
+ unsigned int tmpflags;
+ err |= __get_user(tmpflags, &sc->eflags);
+ regs->eflags = (regs->eflags & ~0x40DD5) | (tmpflags & 0x40DD5);
+ regs->orig_eax = -1; /* disable syscall checks */
+ }
+
+ {
+ struct _fpstate * buf;
+ err |= __get_user(buf, &sc->fpstate);
+ if (buf) {
+ if (verify_area(VERIFY_READ, buf, sizeof(*buf)))
+ goto badframe;
+ err |= restore_i387(buf);
+ }
+ }
+
+ err |= __get_user(*peax, &sc->eax);
+ return err;
+
+badframe:
+ return 1;
+}
+
+asmlinkage int sys_sigreturn(unsigned long __unused)
+{
+ struct pt_regs *regs = (struct pt_regs *) &__unused;
+ struct sigframe *frame = (struct sigframe *)(regs->esp - 8);
+ sigset_t set;
+ int eax;
+
+ if (verify_area(VERIFY_READ, frame, sizeof(*frame)))
+ goto badframe;
+ if (__get_user(set.sig[0], &frame->sc.oldmask)
+ || (_NSIG_WORDS > 1
+ && __copy_from_user(&set.sig[1], &frame->extramask,
+ sizeof(frame->extramask))))
+ goto badframe;
+
+ sigdelsetmask(&set, ~_BLOCKABLE);
+ spin_lock_irq(¤t->sigmask_lock);
+ current->blocked = set;
+ recalc_sigpending(current);
+ spin_unlock_irq(¤t->sigmask_lock);
+
+ if (restore_sigcontext(regs, &frame->sc, &eax))
+ goto badframe;
+ return eax;
+
+badframe:
+ force_sig(SIGSEGV, current);
+ return 0;
+}
+
+asmlinkage int sys_rt_sigreturn(unsigned long __unused)
+{
+ struct pt_regs *regs = (struct pt_regs *) &__unused;
+ struct rt_sigframe *frame = (struct rt_sigframe *)(regs->esp - 4);
+ sigset_t set;
+ stack_t st;
+ int eax;
+
+ if (verify_area(VERIFY_READ, frame, sizeof(*frame)))
+ goto badframe;
+ if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set)))
+ goto badframe;
+
+ sigdelsetmask(&set, ~_BLOCKABLE);
+ spin_lock_irq(¤t->sigmask_lock);
+ current->blocked = set;
+ recalc_sigpending(current);
+ spin_unlock_irq(¤t->sigmask_lock);
+
+ if (restore_sigcontext(regs, &frame->uc.uc_mcontext, &eax))
+ goto badframe;
+
+ if (__copy_from_user(&st, &frame->uc.uc_stack, sizeof(st)))
+ goto badframe;
+ /* It is more difficult to avoid calling this function than to
+ call it and ignore errors. */
+ do_sigaltstack(&st, NULL, regs->esp);
+
+ return eax;
+
+badframe:
+ force_sig(SIGSEGV, current);
+ return 0;
+}
+
+/*
+ * Set up a signal frame.
+ */
+
+static int
+setup_sigcontext(struct sigcontext *sc, struct _fpstate *fpstate,
+ struct pt_regs *regs, unsigned long mask)
+{
+ int tmp, err = 0;
+
+ tmp = 0;
+ __asm__("movl %%gs,%0" : "=r"(tmp): "0"(tmp));
+ err |= __put_user(tmp, (unsigned int *)&sc->gs);
+ __asm__("movl %%fs,%0" : "=r"(tmp): "0"(tmp));
+ err |= __put_user(tmp, (unsigned int *)&sc->fs);
+
+ err |= __put_user(regs->xes, (unsigned int *)&sc->es);
+ err |= __put_user(regs->xds, (unsigned int *)&sc->ds);
+ err |= __put_user(regs->edi, &sc->edi);
+ err |= __put_user(regs->esi, &sc->esi);
+ err |= __put_user(regs->ebp, &sc->ebp);
+ err |= __put_user(regs->esp, &sc->esp);
+ err |= __put_user(regs->ebx, &sc->ebx);
+ err |= __put_user(regs->edx, &sc->edx);
+ err |= __put_user(regs->ecx, &sc->ecx);
+ err |= __put_user(regs->eax, &sc->eax);
+ err |= __put_user(current->thread.trap_no, &sc->trapno);
+ err |= __put_user(current->thread.error_code, &sc->err);
+ err |= __put_user(regs->eip, &sc->eip);
+ err |= __put_user(regs->xcs, (unsigned int *)&sc->cs);
+ err |= __put_user(regs->eflags, &sc->eflags);
+ err |= __put_user(regs->esp, &sc->esp_at_signal);
+ err |= __put_user(regs->xss, (unsigned int *)&sc->ss);
+
+ tmp = save_i387(fpstate);
+ if (tmp < 0)
+ err = 1;
+ else
+ err |= __put_user(tmp ? fpstate : NULL, &sc->fpstate);
+
+ /* non-iBCS2 extensions.. */
+ err |= __put_user(mask, &sc->oldmask);
+ err |= __put_user(current->thread.cr2, &sc->cr2);
+
+ return err;
+}
+
+/*
+ * Determine which stack to use..
+ */
+static inline void *
+get_sigframe(struct k_sigaction *ka, struct pt_regs * regs, size_t frame_size)
+{
+ unsigned long esp;
+
+ /* Default to using normal stack */
+ esp = regs->esp;
+
+ /* This is the X/Open sanctioned signal stack switching. */
+ if (ka->sa.sa_flags & SA_ONSTACK) {
+ if (sas_ss_flags(esp) == 0)
+ esp = current->sas_ss_sp + current->sas_ss_size;
+ }
+
+ /* This is the legacy signal stack switching. */
+ else if ((regs->xss & 0xffff) != __USER_DS &&
+ !(ka->sa.sa_flags & SA_RESTORER) &&
+ ka->sa.sa_restorer) {
+ esp = (unsigned long) ka->sa.sa_restorer;
+ }
+
+ return (void *)((esp - frame_size) & -8ul);
+}
+
+static void setup_frame(int sig, struct k_sigaction *ka,
+ sigset_t *set, struct pt_regs * regs)
+{
+ struct sigframe *frame;
+ int err = 0;
+
+ frame = get_sigframe(ka, regs, sizeof(*frame));
+
+ if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
+ goto give_sigsegv;
+
+ err |= __put_user((current->exec_domain
+ && current->exec_domain->signal_invmap
+ && sig < 32
+ ? current->exec_domain->signal_invmap[sig]
+ : sig),
+ &frame->sig);
+ if (err)
+ goto give_sigsegv;
+
+ err |= setup_sigcontext(&frame->sc, &frame->fpstate, regs, set->sig[0]);
+ if (err)
+ goto give_sigsegv;
+
+ if (_NSIG_WORDS > 1) {
+ err |= __copy_to_user(frame->extramask, &set->sig[1],
+ sizeof(frame->extramask));
+ }
+ if (err)
+ goto give_sigsegv;
+
+ /* Set up to return from userspace. If provided, use a stub
+ already in userspace. */
+ if (ka->sa.sa_flags & SA_RESTORER) {
+ err |= __put_user(ka->sa.sa_restorer, &frame->pretcode);
+ } else {
+ err |= __put_user(frame->retcode, &frame->pretcode);
+ /* This is popl %eax ; movl $,%eax ; int $0x80 */
+ err |= __put_user(0xb858, (short *)(frame->retcode+0));
+ err |= __put_user(__NR_sigreturn, (int *)(frame->retcode+2));
+ err |= __put_user(0x80cd, (short *)(frame->retcode+6));
+ }
+
+ if (err)
+ goto give_sigsegv;
+
+ /* Set up registers for signal handler */
+ regs->esp = (unsigned long) frame;
+ regs->eip = (unsigned long) ka->sa.sa_handler;
+
+ set_fs(USER_DS);
+ regs->xds = __USER_DS;
+ regs->xes = __USER_DS;
+ regs->xss = __USER_DS;
+ regs->xcs = __USER_CS;
+ regs->eflags &= ~TF_MASK;
+
+#if DEBUG_SIG
+ printk("SIG deliver (%s:%d): sp=%p pc=%p ra=%p\n",
+ current->comm, current->pid, frame, regs->eip, frame->pretcode);
+#endif
+
+ return;
+
+give_sigsegv:
+ if (sig == SIGSEGV)
+ ka->sa.sa_handler = SIG_DFL;
+ force_sig(SIGSEGV, current);
+}
+
+static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
+ sigset_t *set, struct pt_regs * regs)
+{
+ struct rt_sigframe *frame;
+ int err = 0;
+
+ frame = get_sigframe(ka, regs, sizeof(*frame));
+
+ if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
+ goto give_sigsegv;
+
+ err |= __put_user((current->exec_domain
+ && current->exec_domain->signal_invmap
+ && sig < 32
+ ? current->exec_domain->signal_invmap[sig]
+ : sig),
+ &frame->sig);
+ err |= __put_user(&frame->info, &frame->pinfo);
+ err |= __put_user(&frame->uc, &frame->puc);
+ err |= copy_siginfo_to_user(&frame->info, info);
+ if (err)
+ goto give_sigsegv;
+
+ /* Create the ucontext. */
+ err |= __put_user(0, &frame->uc.uc_flags);
+ err |= __put_user(0, &frame->uc.uc_link);
+ err |= __put_user(current->sas_ss_sp, &frame->uc.uc_stack.ss_sp);
+ err |= __put_user(sas_ss_flags(regs->esp),
+ &frame->uc.uc_stack.ss_flags);
+ err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size);
+ err |= setup_sigcontext(&frame->uc.uc_mcontext, &frame->fpstate,
+ regs, set->sig[0]);
+ err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
+ if (err)
+ goto give_sigsegv;
+
+ /* Set up to return from userspace. If provided, use a stub
+ already in userspace. */
+ if (ka->sa.sa_flags & SA_RESTORER) {
+ err |= __put_user(ka->sa.sa_restorer, &frame->pretcode);
+ } else {
+ err |= __put_user(frame->retcode, &frame->pretcode);
+ /* This is movl $,%eax ; int $0x80 */
+ err |= __put_user(0xb8, (char *)(frame->retcode+0));
+ err |= __put_user(__NR_rt_sigreturn, (int *)(frame->retcode+1));
+ err |= __put_user(0x80cd, (short *)(frame->retcode+5));
+ }
+
+ if (err)
+ goto give_sigsegv;
+
+ /* Set up registers for signal handler */
+ regs->esp = (unsigned long) frame;
+ regs->eip = (unsigned long) ka->sa.sa_handler;
+
+ set_fs(USER_DS);
+ regs->xds = __USER_DS;
+ regs->xes = __USER_DS;
+ regs->xss = __USER_DS;
+ regs->xcs = __USER_CS;
+ regs->eflags &= ~TF_MASK;
+
+#if DEBUG_SIG
+ printk("SIG deliver (%s:%d): sp=%p pc=%p ra=%p\n",
+ current->comm, current->pid, frame, regs->eip, frame->pretcode);
+#endif
+
+ return;
+
+give_sigsegv:
+ if (sig == SIGSEGV)
+ ka->sa.sa_handler = SIG_DFL;
+ force_sig(SIGSEGV, current);
+}
+
+/*
+ * OK, we're invoking a handler
+ */
+
+static void
+handle_signal(unsigned long sig, struct k_sigaction *ka,
+ siginfo_t *info, sigset_t *oldset, struct pt_regs * regs)
+{
+ /* Are we from a system call? */
+ if (regs->orig_eax >= 0) {
+ /* If so, check system call restarting.. */
+ switch (regs->eax) {
+ case -ERESTARTNOHAND:
+ regs->eax = -EINTR;
+ break;
+
+ case -ERESTARTSYS:
+ if (!(ka->sa.sa_flags & SA_RESTART)) {
+ regs->eax = -EINTR;
+ break;
+ }
+ /* fallthrough */
+ case -ERESTARTNOINTR:
+ regs->eax = regs->orig_eax;
+ regs->eip -= 2;
+ }
+ }
+
+ /* Set up the stack frame */
+ if (ka->sa.sa_flags & SA_SIGINFO)
+ setup_rt_frame(sig, ka, info, oldset, regs);
+ else
+ setup_frame(sig, ka, oldset, regs);
+
+ if (ka->sa.sa_flags & SA_ONESHOT)
+ ka->sa.sa_handler = SIG_DFL;
+
+ if (!(ka->sa.sa_flags & SA_NODEFER)) {
+ spin_lock_irq(¤t->sigmask_lock);
+ sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask);
+ sigaddset(¤t->blocked,sig);
+ recalc_sigpending(current);
+ spin_unlock_irq(¤t->sigmask_lock);
+ }
+}
+
+/*
+ * Note that 'init' is a special process: it doesn't get signals it doesn't
+ * want to handle. Thus you cannot kill init even with a SIGKILL even by
+ * mistake.
+ */
+int do_signal(struct pt_regs *regs, sigset_t *oldset)
+{
+ siginfo_t info;
+ struct k_sigaction *ka;
+
+ /*
+ * We want the common case to go fast, which
+ * is why we may in certain cases get here from
+ * kernel mode. Just return without doing anything
+ * if so.
+ */
+ if ((regs->xcs & 2) != 2)
+ return 1;
+
+ if (!oldset)
+ oldset = ¤t->blocked;
+
+ for (;;) {
+ unsigned long signr;
+
+ spin_lock_irq(¤t->sigmask_lock);
+ signr = dequeue_signal(¤t->blocked, &info);
+ spin_unlock_irq(¤t->sigmask_lock);
+
+ if (!signr)
+ break;
+
+ if ((current->ptrace & PT_PTRACED) && signr != SIGKILL) {
+ /* Let the debugger run. */
+ current->exit_code = signr;
+ current->state = TASK_STOPPED;
+ notify_parent(current, SIGCHLD);
+ schedule();
+
+ /* We're back. Did the debugger cancel the sig? */
+ if (!(signr = current->exit_code))
+ continue;
+ current->exit_code = 0;
+
+ /* The debugger continued. Ignore SIGSTOP. */
+ if (signr == SIGSTOP)
+ continue;
+
+ /* Update the siginfo structure. Is this good? */
+ if (signr != info.si_signo) {
+ info.si_signo = signr;
+ info.si_errno = 0;
+ info.si_code = SI_USER;
+ info.si_pid = current->p_pptr->pid;
+ info.si_uid = current->p_pptr->uid;
+ }
+
+ /* If the (new) signal is now blocked, requeue it. */
+ if (sigismember(¤t->blocked, signr)) {
+ send_sig_info(signr, &info, current);
+ continue;
+ }
+ }
+
+ ka = ¤t->sig->action[signr-1];
+ if (ka->sa.sa_handler == SIG_IGN) {
+ if (signr != SIGCHLD)
+ continue;
+ /* Check for SIGCHLD: it's special. */
+ while (sys_wait4(-1, NULL, WNOHANG, NULL) > 0)
+ /* nothing */;
+ continue;
+ }
+
+ if (ka->sa.sa_handler == SIG_DFL) {
+ int exit_code = signr;
+
+ /* Init gets no signals it doesn't want. */
+ if (current->pid == 1)
+ continue;
+
+ switch (signr) {
+ case SIGCONT: case SIGCHLD: case SIGWINCH: case SIGURG:
+ continue;
+
+ case SIGTSTP: case SIGTTIN: case SIGTTOU:
+ if (is_orphaned_pgrp(current->pgrp))
+ continue;
+ /* FALLTHRU */
+
+ case SIGSTOP: {
+ struct signal_struct *sig;
+ current->state = TASK_STOPPED;
+ current->exit_code = signr;
+ sig = current->p_pptr->sig;
+ if (sig && !(sig->action[SIGCHLD-1].sa.sa_flags & SA_NOCLDSTOP))
+ notify_parent(current, SIGCHLD);
+ schedule();
+ continue;
+ }
+
+ case SIGQUIT: case SIGILL: case SIGTRAP:
+ case SIGABRT: case SIGFPE: case SIGSEGV:
+ case SIGBUS: case SIGSYS: case SIGXCPU: case SIGXFSZ:
+ if (do_coredump(signr, regs))
+ exit_code |= 0x80;
+ /* FALLTHRU */
+
+ default:
+ sig_exit(signr, exit_code, &info);
+ /* NOTREACHED */
+ }
+ }
+
+ /* Reenable any watchpoints before delivering the
+ * signal to user space. The processor register will
+ * have been cleared if the watchpoint triggered
+ * inside the kernel.
+ */
+ if ( current->thread.debugreg[7] != 0 )
+ HYPERVISOR_set_debugreg(7, current->thread.debugreg[7]);
+
+ /* Whee! Actually deliver the signal. */
+ handle_signal(signr, ka, &info, oldset, regs);
+ return 1;
+ }
+
+ /* Did we come from a system call? */
+ if (regs->orig_eax >= 0) {
+ /* Restart the system call - no handlers present */
+ if (regs->eax == -ERESTARTNOHAND ||
+ regs->eax == -ERESTARTSYS ||
+ regs->eax == -ERESTARTNOINTR) {
+ regs->eax = regs->orig_eax;
+ regs->eip -= 2;
+ }
+ }
+ return 0;
+}
--- /dev/null
+/* -*- Mode:C; c-basic-offset:4; tab-width:4 -*-
+ ****************************************************************************
+ * (C) 2002 - Rolf Neugebauer - Intel Research Cambridge
+ ****************************************************************************
+ *
+ * File: arch.xeno/time.c
+ * Author: Rolf Neugebauer
+ * Changes:
+ *
+ * Date: Nov 2002
+ *
+ * Environment: XenoLinux
+ * Description: Interface with Hypervisor to get correct notion of time
+ * Currently supports Systemtime and WallClock time.
+ *
+ * (This has hardly any resemblence with the Linux code but left the
+ * copyright notice anyway. Ignore the comments in the copyright notice.)
+ ****************************************************************************
+ * $Id: c-insert.c,v 1.7 2002/11/08 16:04:34 rn Exp $
+ ****************************************************************************
+ */
+
+/*
+ * linux/arch/i386/kernel/time.c
+ *
+ * Copyright (C) 1991, 1992, 1995 Linus Torvalds
+ *
+ * This file contains the PC-specific time handling details:
+ * reading the RTC at bootup, etc..
+ * 1994-07-02 Alan Modra
+ * fixed set_rtc_mmss, fixed time.year for >= 2000, new mktime
+ * 1995-03-26 Markus Kuhn
+ * fixed 500 ms bug at call to set_rtc_mmss, fixed DS12887
+ * precision CMOS clock update
+ * 1996-05-03 Ingo Molnar
+ * fixed time warps in do_[slow|fast]_gettimeoffset()
+ * 1997-09-10 Updated NTP code according to technical memorandum Jan '96
+ * "A Kernel Model for Precision Timekeeping" by Dave Mills
+ * 1998-09-05 (Various)
+ * More robust do_fast_gettimeoffset() algorithm implemented
+ * (works with APM, Cyrix 6x86MX and Centaur C6),
+ * monotonic gettimeofday() with fast_get_timeoffset(),
+ * drift-proof precision TSC calibration on boot
+ * (C. Scott Ananian <cananian@alumni.princeton.edu>, Andrew D.
+ * Balsa <andrebalsa@altern.org>, Philip Gladstone <philip@raptor.com>;
+ * ported from 2.0.35 Jumbo-9 by Michael Krause <m.krause@tu-harburg.de>).
+ * 1998-12-16 Andrea Arcangeli
+ * Fixed Jumbo-9 code in 2.1.131: do_gettimeofday was missing 1 jiffy
+ * because was not accounting lost_ticks.
+ * 1998-12-24 Copyright (C) 1998 Andrea Arcangeli
+ * Fixed a xtime SMP race (we need the xtime_lock rw spinlock to
+ * serialize accesses to xtime/lost_ticks).
+ */
+
+#include <asm/smp.h>
+#include <asm/irq.h>
+#include <asm/msr.h>
+#include <asm/delay.h>
+#include <asm/mpspec.h>
+#include <asm/uaccess.h>
+#include <asm/processor.h>
+
+#include <asm/div64.h>
+#include <asm/hypervisor.h>
+
+#include <linux/kernel.h>
+#include <linux/interrupt.h>
+#include <linux/time.h>
+#include <linux/init.h>
+#include <linux/smp.h>
+#include <linux/irq.h>
+
+#undef XENO_TIME_DEBUG /* adds sanity checks and periodic printouts */
+
+spinlock_t rtc_lock = SPIN_LOCK_UNLOCKED;
+extern rwlock_t xtime_lock;
+
+unsigned long cpu_khz; /* get this from Xen, used elsewhere */
+static spinlock_t hyp_stime_lock = SPIN_LOCK_UNLOCKED;
+static spinlock_t hyp_wctime_lock = SPIN_LOCK_UNLOCKED;
+
+static u32 st_scale_f;
+static u32 st_scale_i;
+static u32 shadow_st_pcc;
+static s64 shadow_st;
+
+/*
+ * System time.
+ * Although the rest of the Linux kernel doesn't know about this, we
+ * we use it to extrapolate passage of wallclock time.
+ * We need to read the values from the shared info page "atomically"
+ * and use the cycle counter value as the "version" number. Clashes
+ * should be very rare.
+ */
+static inline long long get_s_time(void)
+{
+ unsigned long flags;
+ u32 delta_tsc, low, pcc;
+ u64 delta;
+ s64 now;
+
+ spin_lock_irqsave(&hyp_stime_lock, flags);
+
+ while ((pcc = HYPERVISOR_shared_info->st_timestamp) != shadow_st_pcc)
+ {
+ barrier();
+ shadow_st_pcc = pcc;
+ shadow_st = HYPERVISOR_shared_info->system_time;
+ barrier();
+ }
+
+ now = shadow_st;
+ /* only use bottom 32bits of TSC. This should be sufficient */
+ rdtscl(low);
+ delta_tsc = low - pcc;
+ delta = ((u64)delta_tsc * st_scale_f);
+ delta >>= 32;
+ delta += ((u64)delta_tsc * st_scale_i);
+
+ spin_unlock_irqrestore(&hyp_time_lock, flags);
+
+ return now + delta;
+
+}
+#define NOW() ((long long)get_s_time())
+
+/*
+ * Wallclock time.
+ * Based on what the hypervisor tells us, extrapolated using system time.
+ * Again need to read a number of values from the shared page "atomically".
+ * this time using a version number.
+ */
+static u32 shadow_wc_version=0;
+static long shadow_tv_sec;
+static long shadow_tv_usec;
+static long long shadow_wc_timestamp;
+void do_gettimeofday(struct timeval *tv)
+{
+ unsigned long flags;
+ long usec, sec;
+ u32 version;
+ u64 now;
+
+ spin_lock_irqsave(&hyp_wctime_lock, flags);
+
+ while ((version = HYPERVISOR_shared_info->wc_version)!= shadow_wc_version)
+ {
+ barrier();
+ shadow_wc_version = version;
+ shadow_tv_sec = HYPERVISOR_shared_info->tv_sec;
+ shadow_tv_usec = HYPERVISOR_shared_info->tv_usec;
+ shadow_wc_timestamp = HYPERVISOR_shared_info->wc_timestamp;
+ barrier();
+ }
+
+ now = NOW();
+ usec = ((unsigned long)(now-shadow_wc_timestamp))/1000;
+ sec = shadow_tv_sec;
+ usec += shadow_tv_usec;
+
+ while ( usec >= 1000000 )
+ {
+ usec -= 1000000;
+ sec++;
+ }
+
+ tv->tv_sec = sec;
+ tv->tv_usec = usec;
+
+ spin_unlock_irqrestore(&hyp_time_lock, flags);
+
+#ifdef XENO_TIME_DEBUG
+ {
+ static long long old_now=0;
+ static long long wct=0, old_wct=0;
+
+ /* This debug code checks if time increase over two subsequent calls */
+ wct=(((long long)sec) * 1000000) + usec;
+ /* wall clock time going backwards */
+ if ((wct < old_wct) ) {
+ printk("Urgh1: wc diff=%6ld, usec = %ld (0x%lX)\n",
+ (long)(wct-old_wct), usec, usec);
+ printk(" st diff=%lld cur st=0x%016llX old st=0x%016llX\n",
+ now-old_now, now, old_now);
+ }
+
+ /* system time going backwards */
+ if (now<=old_now) {
+ printk("Urgh2: st diff=%lld cur st=0x%016llX old st=0x%016llX\n",
+ now-old_now, now, old_now);
+ }
+ old_wct = wct;
+ old_now = now;
+ }
+#endif
+
+}
+
+void do_settimeofday(struct timeval *tv)
+{
+/* XXX RN: should do something special here for dom0 */
+#if 0
+ write_lock_irq(&xtime_lock);
+ /*
+ * This is revolting. We need to set "xtime" correctly. However, the
+ * value in this location is the value at the most recent update of
+ * wall time. Discover what correction gettimeofday() would have
+ * made, and then undo it!
+ */
+ tv->tv_usec -= do_gettimeoffset();
+ tv->tv_usec -= (jiffies - wall_jiffies) * (1000000 / HZ);
+
+ while ( tv->tv_usec < 0 )
+ {
+ tv->tv_usec += 1000000;
+ tv->tv_sec--;
+ }
+
+ xtime = *tv;
+ time_adjust = 0; /* stop active adjtime() */
+ time_status |= STA_UNSYNC;
+ time_maxerror = NTP_PHASE_LIMIT;
+ time_esterror = NTP_PHASE_LIMIT;
+ write_unlock_irq(&xtime_lock);
+#endif
+}
+
+
+/*
+ * Timer ISR.
+ * Unlike normal Linux these don't come in at a fixed rate of HZ.
+ * In here we wrok out how often it should have been called and then call
+ * the architecture independent part (do_timer()) the appropriate number of
+ * times. A bit of a nasty hack, to keep the "other" notion of wallclock time
+ * happy.
+ */
+static long long us_per_tick=1000000/HZ;
+static long long last_irq;
+static inline void do_timer_interrupt(int irq, void *dev_id,
+ struct pt_regs *regs)
+{
+ struct timeval tv;
+ long long time, delta;
+
+#ifdef XENO_TIME_DEBUG
+ static u32 foo_count = 0;
+ foo_count++;
+ if (foo_count>= 1000) {
+ s64 n = NOW();
+ struct timeval tv;
+ do_gettimeofday(&tv);
+ printk("0x%08X%08X %ld:%ld\n",
+ (u32)(n>>32), (u32)n, tv.tv_sec, tv.tv_usec);
+ foo_count = 0;
+ }
+#endif
+ /*
+ * The next bit really sucks:
+ * Linux not only uses do_gettimeofday() to keep a notion of
+ * wallclock time, but also maintains the xtime struct and jiffies.
+ * (Even worse some userland code accesses this via the sys_time()
+ * system call)
+ * Unfortunately, xtime is maintain in the architecture independent
+ * part of the timer ISR (./kernel/timer.c sic!). So, although we have
+ * perfectly valid notion of wallclock time from the hypervisor we here
+ * fake missed timer interrupts so that the arch independent part of
+ * the Timer ISR updates jiffies for us *and* once the bh gets run
+ * updates xtime accordingly. Yuck!
+ */
+
+ /* work out the number of jiffies past and update them */
+ do_gettimeofday(&tv);
+ time = (((long long)tv.tv_sec) * 1000000) + tv.tv_usec;
+ delta = time - last_irq;
+ if (delta <= 0) {
+ printk ("Timer ISR: Time went backwards: %lld\n", delta);
+ return;
+ }
+ while (delta >= us_per_tick) {
+ do_timer(regs);
+ delta -= us_per_tick;
+ last_irq += us_per_tick;
+ }
+
+#if 0
+ if (!user_mode(regs))
+ x86_do_profile(regs->eip);
+#endif
+}
+
+static void timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+ write_lock(&xtime_lock);
+ do_timer_interrupt(irq, NULL, regs);
+ write_unlock(&xtime_lock);
+}
+
+static struct irqaction irq_timer = {
+ timer_interrupt,
+ SA_INTERRUPT,
+ 0,
+ "timer",
+ NULL,
+ NULL
+};
+
+void __init time_init(void)
+{
+ unsigned long long alarm;
+ u64 cpu_freq = HYPERVISOR_shared_info->cpu_freq;
+ u64 scale;
+
+ cpu_khz = (u32)cpu_freq/1000;
+ printk("Xen reported: %lu.%03lu MHz processor.\n",
+ cpu_khz / 1000, cpu_khz % 1000);
+
+ /*
+ * calculate systemtime scaling factor
+ * XXX RN: have to cast cpu_freq to u32 limits it to 4.29 GHz.
+ * Get a better do_div!
+ */
+ scale = 1000000000LL << 32;
+ do_div(scale,(u32)cpu_freq);
+ st_scale_f = scale & 0xffffffff;
+ st_scale_i = scale >> 32;
+ printk("System Time scale: %X %X\n",st_scale_i, st_scale_f);
+
+ do_gettimeofday(&xtime);
+ last_irq = (((long long)xtime.tv_sec) * 1000000) + xtime.tv_usec;
+
+ setup_irq(TIMER_IRQ, &irq_timer);
+
+ /*
+ * Start ticker. Note that timing runs of wall clock, not virtual
+ * 'domain' time. This means that clock sshould run at the correct
+ * rate. For things like scheduling, it's not clear whether it
+ * matters which sort of time we use.
+ * XXX RN: unimplemented.
+ */
+
+ rdtscll(alarm);
+#if 0
+ alarm += (1000/HZ)*HYPERVISOR_shared_info->ticks_per_ms;
+ HYPERVISOR_shared_info->wall_timeout = alarm;
+ HYPERVISOR_shared_info->domain_timeout = ~0ULL;
+#endif
+ clear_bit(_EVENT_TIMER, &HYPERVISOR_shared_info->events);
+}
--- /dev/null
+/*
+ * linux/arch/i386/traps.c
+ *
+ * Copyright (C) 1991, 1992 Linus Torvalds
+ *
+ * Pentium III FXSR, SSE support
+ * Gareth Hughes <gareth@valinux.com>, May 2000
+ */
+
+/*
+ * 'Traps.c' handles hardware traps and faults after we have saved some
+ * state in 'asm.s'.
+ */
+#include <linux/config.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/ptrace.h>
+#include <linux/timer.h>
+#include <linux/mm.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/spinlock.h>
+#include <linux/interrupt.h>
+#include <linux/highmem.h>
+
+#include <asm/system.h>
+#include <asm/uaccess.h>
+#include <asm/io.h>
+#include <asm/atomic.h>
+#include <asm/debugreg.h>
+#include <asm/desc.h>
+#include <asm/i387.h>
+
+#include <asm/smp.h>
+#include <asm/pgalloc.h>
+
+#include <asm/hypervisor.h>
+
+#include <linux/irq.h>
+#include <linux/module.h>
+
+asmlinkage int system_call(void);
+asmlinkage void lcall7(void);
+asmlinkage void lcall27(void);
+
+asmlinkage void divide_error(void);
+asmlinkage void debug(void);
+asmlinkage void int3(void);
+asmlinkage void overflow(void);
+asmlinkage void bounds(void);
+asmlinkage void invalid_op(void);
+asmlinkage void device_not_available(void);
+asmlinkage void double_fault(void);
+asmlinkage void coprocessor_segment_overrun(void);
+asmlinkage void invalid_TSS(void);
+asmlinkage void segment_not_present(void);
+asmlinkage void stack_segment(void);
+asmlinkage void general_protection(void);
+asmlinkage void page_fault(void);
+asmlinkage void coprocessor_error(void);
+asmlinkage void simd_coprocessor_error(void);
+asmlinkage void alignment_check(void);
+asmlinkage void spurious_interrupt_bug(void);
+asmlinkage void machine_check(void);
+
+int kstack_depth_to_print = 24;
+
+
+/*
+ * If the address is either in the .text section of the
+ * kernel, or in the vmalloc'ed module regions, it *may*
+ * be the address of a calling routine
+ */
+
+#ifdef CONFIG_MODULES
+
+extern struct module *module_list;
+extern struct module kernel_module;
+
+static inline int kernel_text_address(unsigned long addr)
+{
+ int retval = 0;
+ struct module *mod;
+
+ if (addr >= (unsigned long) &_stext &&
+ addr <= (unsigned long) &_etext)
+ return 1;
+
+ for (mod = module_list; mod != &kernel_module; mod = mod->next) {
+ /* mod_bound tests for addr being inside the vmalloc'ed
+ * module area. Of course it'd be better to test only
+ * for the .text subset... */
+ if (mod_bound(addr, 0, mod)) {
+ retval = 1;
+ break;
+ }
+ }
+
+ return retval;
+}
+
+#else
+
+static inline int kernel_text_address(unsigned long addr)
+{
+ return (addr >= (unsigned long) &_stext &&
+ addr <= (unsigned long) &_etext);
+}
+
+#endif
+
+void show_trace(unsigned long * stack)
+{
+ int i;
+ unsigned long addr;
+
+ if (!stack)
+ stack = (unsigned long*)&stack;
+
+ printk("Call Trace: ");
+ i = 1;
+ while (((long) stack & (THREAD_SIZE-1)) != 0) {
+ addr = *stack++;
+ if (kernel_text_address(addr)) {
+ if (i && ((i % 6) == 0))
+ printk("\n ");
+ printk("[<%08lx>] ", addr);
+ i++;
+ }
+ }
+ printk("\n");
+}
+
+void show_trace_task(struct task_struct *tsk)
+{
+ unsigned long esp = tsk->thread.esp;
+
+ /* User space on another CPU? */
+ if ((esp ^ (unsigned long)tsk) & (PAGE_MASK<<1))
+ return;
+ show_trace((unsigned long *)esp);
+}
+
+void show_stack(unsigned long * esp)
+{
+ unsigned long *stack;
+ int i;
+
+ // debugging aid: "show_stack(NULL);" prints the
+ // back trace for this cpu.
+
+ if(esp==NULL)
+ esp=(unsigned long*)&esp;
+
+ stack = esp;
+ for(i=0; i < kstack_depth_to_print; i++) {
+ if (((long) stack & (THREAD_SIZE-1)) == 0)
+ break;
+ if (i && ((i % 8) == 0))
+ printk("\n ");
+ printk("%08lx ", *stack++);
+ }
+ printk("\n");
+ show_trace(esp);
+}
+
+void show_registers(struct pt_regs *regs)
+{
+ int i;
+ int in_kernel = 1;
+ unsigned long esp;
+ unsigned short ss;
+
+ esp = (unsigned long) (®s->esp);
+ ss = __KERNEL_DS;
+ if (regs->xcs & 2) {
+ in_kernel = 0;
+ esp = regs->esp;
+ ss = regs->xss & 0xffff;
+ }
+ printk("CPU: %d\nEIP: %04x:[<%08lx>] %s\nEFLAGS: %08lx\n",
+ smp_processor_id(), 0xffff & regs->xcs, regs->eip, print_tainted(), regs->eflags);
+ printk("eax: %08lx ebx: %08lx ecx: %08lx edx: %08lx\n",
+ regs->eax, regs->ebx, regs->ecx, regs->edx);
+ printk("esi: %08lx edi: %08lx ebp: %08lx esp: %08lx\n",
+ regs->esi, regs->edi, regs->ebp, esp);
+ printk("ds: %04x es: %04x ss: %04x\n",
+ regs->xds & 0xffff, regs->xes & 0xffff, ss);
+ printk("Process %s (pid: %d, stackpage=%08lx)",
+ current->comm, current->pid, 4096+(unsigned long)current);
+ /*
+ * When in-kernel, we also print out the stack and code at the
+ * time of the fault..
+ */
+ if (in_kernel) {
+
+ printk("\nStack: ");
+ show_stack((unsigned long*)esp);
+
+#if 0
+ printk("\nCode: ");
+ if(regs->eip < PAGE_OFFSET)
+ goto bad;
+
+ for(i=0;i<20;i++)
+ {
+ unsigned char c;
+ if(__get_user(c, &((unsigned char*)regs->eip)[i])) {
+bad:
+ printk(" Bad EIP value.");
+ break;
+ }
+ printk("%02x ", c);
+ }
+#endif
+ }
+ printk("\n");
+}
+
+spinlock_t die_lock = SPIN_LOCK_UNLOCKED;
+
+void die(const char * str, struct pt_regs * regs, long err)
+{
+ console_verbose();
+ spin_lock_irq(&die_lock);
+ bust_spinlocks(1);
+ printk("%s: %04lx\n", str, err & 0xffff);
+ show_registers(regs);
+ bust_spinlocks(0);
+ spin_unlock_irq(&die_lock);
+ do_exit(SIGSEGV);
+}
+
+static inline void die_if_kernel(const char * str, struct pt_regs * regs, long err)
+{
+ if (!(2 & regs->xcs))
+ die(str, regs, err);
+}
+
+
+static void inline do_trap(int trapnr, int signr, char *str,
+ struct pt_regs * regs, long error_code,
+ siginfo_t *info)
+{
+ if (!(regs->xcs & 2))
+ goto kernel_trap;
+
+ /*trap_signal:*/ {
+ struct task_struct *tsk = current;
+ tsk->thread.error_code = error_code;
+ tsk->thread.trap_no = trapnr;
+ if (info)
+ force_sig_info(signr, info, tsk);
+ else
+ force_sig(signr, tsk);
+ return;
+ }
+
+ kernel_trap: {
+ unsigned long fixup = search_exception_table(regs->eip);
+ if (fixup)
+ regs->eip = fixup;
+ else
+ die(str, regs, error_code);
+ return;
+ }
+}
+
+#define DO_ERROR(trapnr, signr, str, name) \
+asmlinkage void do_##name(struct pt_regs * regs, long error_code) \
+{ \
+ do_trap(trapnr, signr, str, regs, error_code, NULL); \
+}
+
+#define DO_ERROR_INFO(trapnr, signr, str, name, sicode, siaddr) \
+asmlinkage void do_##name(struct pt_regs * regs, long error_code) \
+{ \
+ siginfo_t info; \
+ info.si_signo = signr; \
+ info.si_errno = 0; \
+ info.si_code = sicode; \
+ info.si_addr = (void *)siaddr; \
+ do_trap(trapnr, signr, str, regs, error_code, &info); \
+}
+
+DO_ERROR_INFO( 0, SIGFPE, "divide error", divide_error, FPE_INTDIV, regs->eip)
+DO_ERROR( 3, SIGTRAP, "int3", int3)
+DO_ERROR( 4, SIGSEGV, "overflow", overflow)
+DO_ERROR( 5, SIGSEGV, "bounds", bounds)
+DO_ERROR_INFO( 6, SIGILL, "invalid operand", invalid_op, ILL_ILLOPN, regs->eip)
+DO_ERROR( 7, SIGSEGV, "device not available", device_not_available)
+DO_ERROR( 8, SIGSEGV, "double fault", double_fault)
+DO_ERROR( 9, SIGFPE, "coprocessor segment overrun", coprocessor_segment_overrun)
+DO_ERROR(10, SIGSEGV, "invalid TSS", invalid_TSS)
+DO_ERROR(11, SIGBUS, "segment not present", segment_not_present)
+DO_ERROR(12, SIGBUS, "stack segment", stack_segment)
+DO_ERROR_INFO(17, SIGBUS, "alignment check", alignment_check, BUS_ADRALN, 0)
+DO_ERROR(18, SIGBUS, "machine check", machine_check)
+
+asmlinkage void do_general_protection(struct pt_regs * regs, long error_code)
+{
+ if (!(regs->xcs & 2))
+ goto gp_in_kernel;
+
+ current->thread.error_code = error_code;
+ current->thread.trap_no = 13;
+ force_sig(SIGSEGV, current);
+ return;
+
+gp_in_kernel:
+ {
+ unsigned long fixup;
+ fixup = search_exception_table(regs->eip);
+ if (fixup) {
+ regs->eip = fixup;
+ return;
+ }
+ die("general protection fault", regs, error_code);
+ }
+}
+
+
+asmlinkage void do_debug(struct pt_regs * regs, long error_code)
+{
+ unsigned int condition;
+ struct task_struct *tsk = current;
+ siginfo_t info;
+
+ condition = HYPERVISOR_get_debugreg(6);
+
+ /* Mask out spurious debug traps due to lazy DR7 setting */
+ if (condition & (DR_TRAP0|DR_TRAP1|DR_TRAP2|DR_TRAP3)) {
+ if (!tsk->thread.debugreg[7])
+ goto clear_dr7;
+ }
+
+ /* Save debug status register where ptrace can see it */
+ tsk->thread.debugreg[6] = condition;
+
+ /* Mask out spurious TF errors due to lazy TF clearing */
+ if (condition & DR_STEP) {
+ /*
+ * The TF error should be masked out only if the current
+ * process is not traced and if the TRAP flag has been set
+ * previously by a tracing process (condition detected by
+ * the PT_DTRACE flag); remember that the i386 TRAP flag
+ * can be modified by the process itself in user mode,
+ * allowing programs to debug themselves without the ptrace()
+ * interface.
+ */
+ if ((tsk->ptrace & (PT_DTRACE|PT_PTRACED)) == PT_DTRACE)
+ goto clear_TF;
+ }
+
+ /* Ok, finally something we can handle */
+ tsk->thread.trap_no = 1;
+ tsk->thread.error_code = error_code;
+ info.si_signo = SIGTRAP;
+ info.si_errno = 0;
+ info.si_code = TRAP_BRKPT;
+
+ /* If this is a kernel mode trap, save the user PC on entry to
+ * the kernel, that's what the debugger can make sense of.
+ */
+ info.si_addr = ((regs->xcs & 2) == 0) ? (void *)tsk->thread.eip :
+ (void *)regs->eip;
+ force_sig_info(SIGTRAP, &info, tsk);
+
+ /* Disable additional traps. They'll be re-enabled when
+ * the signal is delivered.
+ */
+ clear_dr7:
+ HYPERVISOR_set_debugreg(7, 0);
+ return;
+
+ clear_TF:
+ regs->eflags &= ~TF_MASK;
+ return;
+}
+
+
+/*
+ * Note that we play around with the 'TS' bit in an attempt to get
+ * the correct behaviour even in the presence of the asynchronous
+ * IRQ13 behaviour
+ */
+void math_error(void *eip)
+{
+ struct task_struct * task;
+ siginfo_t info;
+ unsigned short cwd, swd;
+
+ /*
+ * Save the info for the exception handler and clear the error.
+ */
+ task = current;
+ save_init_fpu(task);
+ task->thread.trap_no = 16;
+ task->thread.error_code = 0;
+ info.si_signo = SIGFPE;
+ info.si_errno = 0;
+ info.si_code = __SI_FAULT;
+ info.si_addr = eip;
+ /*
+ * (~cwd & swd) will mask out exceptions that are not set to unmasked
+ * status. 0x3f is the exception bits in these regs, 0x200 is the
+ * C1 reg you need in case of a stack fault, 0x040 is the stack
+ * fault bit. We should only be taking one exception at a time,
+ * so if this combination doesn't produce any single exception,
+ * then we have a bad program that isn't syncronizing its FPU usage
+ * and it will suffer the consequences since we won't be able to
+ * fully reproduce the context of the exception
+ */
+ cwd = get_fpu_cwd(task);
+ swd = get_fpu_swd(task);
+ switch (((~cwd) & swd & 0x3f) | (swd & 0x240)) {
+ case 0x000:
+ default:
+ break;
+ case 0x001: /* Invalid Op */
+ case 0x040: /* Stack Fault */
+ case 0x240: /* Stack Fault | Direction */
+ info.si_code = FPE_FLTINV;
+ break;
+ case 0x002: /* Denormalize */
+ case 0x010: /* Underflow */
+ info.si_code = FPE_FLTUND;
+ break;
+ case 0x004: /* Zero Divide */
+ info.si_code = FPE_FLTDIV;
+ break;
+ case 0x008: /* Overflow */
+ info.si_code = FPE_FLTOVF;
+ break;
+ case 0x020: /* Precision */
+ info.si_code = FPE_FLTRES;
+ break;
+ }
+ force_sig_info(SIGFPE, &info, task);
+}
+
+asmlinkage void do_coprocessor_error(struct pt_regs * regs, long error_code)
+{
+ ignore_irq13 = 1;
+ math_error((void *)regs->eip);
+}
+
+void simd_math_error(void *eip)
+{
+ struct task_struct * task;
+ siginfo_t info;
+ unsigned short mxcsr;
+
+ /*
+ * Save the info for the exception handler and clear the error.
+ */
+ task = current;
+ save_init_fpu(task);
+ task->thread.trap_no = 19;
+ task->thread.error_code = 0;
+ info.si_signo = SIGFPE;
+ info.si_errno = 0;
+ info.si_code = __SI_FAULT;
+ info.si_addr = eip;
+ /*
+ * The SIMD FPU exceptions are handled a little differently, as there
+ * is only a single status/control register. Thus, to determine which
+ * unmasked exception was caught we must mask the exception mask bits
+ * at 0x1f80, and then use these to mask the exception bits at 0x3f.
+ */
+ mxcsr = get_fpu_mxcsr(task);
+ switch (~((mxcsr & 0x1f80) >> 7) & (mxcsr & 0x3f)) {
+ case 0x000:
+ default:
+ break;
+ case 0x001: /* Invalid Op */
+ info.si_code = FPE_FLTINV;
+ break;
+ case 0x002: /* Denormalize */
+ case 0x010: /* Underflow */
+ info.si_code = FPE_FLTUND;
+ break;
+ case 0x004: /* Zero Divide */
+ info.si_code = FPE_FLTDIV;
+ break;
+ case 0x008: /* Overflow */
+ info.si_code = FPE_FLTOVF;
+ break;
+ case 0x020: /* Precision */
+ info.si_code = FPE_FLTRES;
+ break;
+ }
+ force_sig_info(SIGFPE, &info, task);
+}
+
+asmlinkage void do_simd_coprocessor_error(struct pt_regs * regs,
+ long error_code)
+{
+ if (cpu_has_xmm) {
+ /* Handle SIMD FPU exceptions on PIII+ processors. */
+ ignore_irq13 = 1;
+ simd_math_error((void *)regs->eip);
+ } else {
+ die_if_kernel("cache flush denied", regs, error_code);
+ current->thread.trap_no = 19;
+ current->thread.error_code = error_code;
+ force_sig(SIGSEGV, current);
+ }
+}
+
+asmlinkage void do_spurious_interrupt_bug(struct pt_regs * regs,
+ long error_code)
+{
+}
+
+/*
+ * 'math_state_restore()' saves the current math information in the
+ * old math state array, and gets the new ones from the current task
+ *
+ * Careful.. There are problems with IBM-designed IRQ13 behaviour.
+ * Don't touch unless you *really* know how it works.
+ */
+asmlinkage void math_state_restore(struct pt_regs regs)
+{
+ if (current->used_math) {
+ restore_fpu(current);
+ } else {
+ init_fpu();
+ }
+ current->flags |= PF_USEDFPU; /* So we fnsave on switch_to() */
+}
+
+
+#define _set_gate(gate_addr,type,dpl,addr) \
+do { \
+ int __d0, __d1; \
+ __asm__ __volatile__ ("movw %%dx,%%ax\n\t" \
+ "movw %4,%%dx\n\t" \
+ "movl %%eax,%0\n\t" \
+ "movl %%edx,%1" \
+ :"=m" (*((long *) (gate_addr))), \
+ "=m" (*(1+(long *) (gate_addr))), "=&a" (__d0), "=&d" (__d1) \
+ :"i" ((short) (0x8000+(dpl<<13)+(type<<8))), \
+ "3" ((char *) (addr)),"2" (__KERNEL_CS << 16)); \
+} while (0)
+
+static void __init set_call_gate(void *a, void *addr)
+{
+ _set_gate(a,12,3,addr);
+}
+
+
+static trap_info_t trap_table[] = {
+ { 0, 0, __KERNEL_CS, (unsigned long)divide_error },
+ { 1, 0, __KERNEL_CS, (unsigned long)debug },
+ { 3, 3, __KERNEL_CS, (unsigned long)int3 },
+ { 4, 3, __KERNEL_CS, (unsigned long)overflow },
+ { 5, 3, __KERNEL_CS, (unsigned long)bounds },
+ { 6, 0, __KERNEL_CS, (unsigned long)invalid_op },
+ { 7, 0, __KERNEL_CS, (unsigned long)device_not_available },
+ { 8, 0, __KERNEL_CS, (unsigned long)double_fault },
+ { 9, 0, __KERNEL_CS, (unsigned long)coprocessor_segment_overrun },
+ { 10, 0, __KERNEL_CS, (unsigned long)invalid_TSS },
+ { 11, 0, __KERNEL_CS, (unsigned long)segment_not_present },
+ { 12, 0, __KERNEL_CS, (unsigned long)stack_segment },
+ { 13, 0, __KERNEL_CS, (unsigned long)general_protection },
+ { 14, 0, __KERNEL_CS, (unsigned long)page_fault },
+ { 15, 0, __KERNEL_CS, (unsigned long)spurious_interrupt_bug },
+ { 16, 0, __KERNEL_CS, (unsigned long)coprocessor_error },
+ { 17, 0, __KERNEL_CS, (unsigned long)alignment_check },
+ { 18, 0, __KERNEL_CS, (unsigned long)machine_check },
+ { 19, 0, __KERNEL_CS, (unsigned long)simd_coprocessor_error },
+ { SYSCALL_VECTOR,
+ 3, __KERNEL_CS, (unsigned long)system_call },
+ { 0, 0, 0, 0 }
+};
+
+
+
+void __init trap_init(void)
+{
+ HYPERVISOR_set_trap_table(trap_table);
+ HYPERVISOR_set_fast_trap(SYSCALL_VECTOR);
+
+ /*
+ * The default LDT is a single-entry callgate to lcall7 for iBCS and a
+ * callgate to lcall27 for Solaris/x86 binaries.
+ */
+ clear_page(&default_ldt[0]);
+ set_call_gate(&default_ldt[0],lcall7);
+ set_call_gate(&default_ldt[4],lcall27);
+ __make_page_readonly(&default_ldt[0]);
+
+ cpu_init();
+}
--- /dev/null
+
+.S.o:
+ $(CC) $(AFLAGS) -c $< -o $*.o
+
+L_TARGET = lib.a
+
+obj-y = checksum.o old-checksum.o delay.o \
+ usercopy.o getuser.o \
+ memcpy.o strstr.o
+
+obj-$(CONFIG_X86_USE_3DNOW) += mmx.o
+obj-$(CONFIG_HAVE_DEC_LOCK) += dec_and_lock.o
+obj-$(CONFIG_DEBUG_IOVIRT) += iodebug.o
+
+include $(TOPDIR)/Rules.make
--- /dev/null
+/*
+ * Precise Delay Loops for i386
+ *
+ * Copyright (C) 1993 Linus Torvalds
+ * Copyright (C) 1997 Martin Mares <mj@atrey.karlin.mff.cuni.cz>
+ *
+ * The __delay function must _NOT_ be inlined as its execution time
+ * depends wildly on alignment on many x86 processors. The additional
+ * jump magic is needed to get the timing stable on all the CPU's
+ * we have to worry about.
+ */
+
+#include <linux/config.h>
+#include <linux/sched.h>
+#include <linux/delay.h>
+#include <asm/processor.h>
+#include <asm/delay.h>
+
+#ifdef CONFIG_SMP
+#include <asm/smp.h>
+#endif
+
+void __delay(unsigned long loops)
+{
+ unsigned long bclock, now;
+
+ rdtscl(bclock);
+ do
+ {
+ rep_nop();
+ rdtscl(now);
+ } while ((now-bclock) < loops);
+}
+
+inline void __const_udelay(unsigned long xloops)
+{
+ int d0;
+ __asm__("mull %0"
+ :"=d" (xloops), "=&a" (d0)
+ :"1" (xloops),"0" (current_cpu_data.loops_per_jiffy));
+ __delay(xloops * HZ);
+}
+
+void __udelay(unsigned long usecs)
+{
+ __const_udelay(usecs * 0x000010c6); /* 2**32 / 1000000 */
+}
+
+void __ndelay(unsigned long nsecs)
+{
+ __const_udelay(nsecs * 0x00005); /* 2**32 / 1000000000 (rounded up) */
+}
--- /dev/null
+#
+# Makefile for the linux i386-specific parts of the memory manager.
+#
+# Note! Dependencies are done automagically by 'make dep', which also
+# removes any old dependencies. DON'T put your own dependencies here
+# unless it's something special (ie not a .c file).
+#
+# Note 2! The CFLAGS definition is now in the main makefile...
+
+O_TARGET := mm.o
+
+obj-y := init.o fault.o extable.o pageattr.o hypervisor.o get_unmapped_area.o mmu_context.o
+
+export-objs := pageattr.o
+
+include $(TOPDIR)/Rules.make
--- /dev/null
+/*
+ * linux/arch/i386/mm/fault.c
+ *
+ * Copyright (C) 1995 Linus Torvalds
+ */
+
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/types.h>
+#include <linux/ptrace.h>
+#include <linux/mman.h>
+#include <linux/mm.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <linux/tty.h>
+#include <linux/vt_kern.h> /* For unblank_screen() */
+
+#include <asm/system.h>
+#include <asm/uaccess.h>
+#include <asm/pgalloc.h>
+#include <asm/hardirq.h>
+
+extern void die(const char *,struct pt_regs *,long);
+
+pgd_t *cur_pgd;
+
+/*
+ * Ugly, ugly, but the goto's result in better assembly..
+ */
+int __verify_write(const void * addr, unsigned long size)
+{
+ struct vm_area_struct * vma;
+ unsigned long start = (unsigned long) addr;
+
+ if (!size)
+ return 1;
+
+ vma = find_vma(current->mm, start);
+ if (!vma)
+ goto bad_area;
+ if (vma->vm_start > start)
+ goto check_stack;
+
+good_area:
+ if (!(vma->vm_flags & VM_WRITE))
+ goto bad_area;
+ size--;
+ size += start & ~PAGE_MASK;
+ size >>= PAGE_SHIFT;
+ start &= PAGE_MASK;
+
+ for (;;) {
+ survive:
+ {
+ int fault = handle_mm_fault(current->mm, vma, start, 1);
+ if (!fault)
+ goto bad_area;
+ if (fault < 0)
+ goto out_of_memory;
+ }
+ if (!size)
+ break;
+ size--;
+ start += PAGE_SIZE;
+ if (start < vma->vm_end)
+ continue;
+ vma = vma->vm_next;
+ if (!vma || vma->vm_start != start)
+ goto bad_area;
+ if (!(vma->vm_flags & VM_WRITE))
+ goto bad_area;;
+ }
+ return 1;
+
+check_stack:
+ if (!(vma->vm_flags & VM_GROWSDOWN))
+ goto bad_area;
+ if (expand_stack(vma, start) == 0)
+ goto good_area;
+
+bad_area:
+ return 0;
+
+out_of_memory:
+ if (current->pid == 1) {
+ yield();
+ goto survive;
+ }
+ goto bad_area;
+}
+
+extern spinlock_t timerlist_lock;
+
+/*
+ * Unlock any spinlocks which will prevent us from getting the
+ * message out (timerlist_lock is acquired through the
+ * console unblank code)
+ */
+void bust_spinlocks(int yes)
+{
+ spin_lock_init(&timerlist_lock);
+ if (yes) {
+ oops_in_progress = 1;
+ } else {
+ int loglevel_save = console_loglevel;
+#ifdef CONFIG_VT
+ unblank_screen();
+#endif
+ oops_in_progress = 0;
+ /*
+ * OK, the message is on the console. Now we call printk()
+ * without oops_in_progress set so that printk will give klogd
+ * a poke. Hold onto your hats...
+ */
+ console_loglevel = 15; /* NMI oopser may have shut the console up */
+ printk(" ");
+ console_loglevel = loglevel_save;
+ }
+}
+
+/*
+ * This routine handles page faults. It determines the address,
+ * and the problem, and then passes it off to one of the appropriate
+ * routines.
+ *
+ * error_code:
+ * bit 0 == 0 means no page found, 1 means protection fault
+ * bit 1 == 0 means read, 1 means write
+ * bit 2 == 0 means kernel, 1 means user-mode
+ */
+asmlinkage void do_page_fault(struct pt_regs *regs,
+ unsigned long error_code,
+ unsigned long address)
+{
+ struct task_struct *tsk = current;
+ struct mm_struct *mm;
+ struct vm_area_struct * vma;
+ unsigned long page;
+ unsigned long fixup;
+ int write;
+ siginfo_t info;
+
+ /* Set the "privileged fault" bit to something sane. */
+ error_code &= 3;
+ error_code |= (regs->xcs & 2) << 1;
+
+#if PT_UPDATE_DEBUG > 0
+ if ( (error_code == 0) && (address >= TASK_SIZE) )
+ {
+ unsigned long paddr = __pa(address);
+ int i;
+ for ( i = 0; i < pt_update_queue_idx; i++ )
+ {
+ if ( update_debug_queue[i].ptr == paddr )
+ {
+ printk("XXX now(EIP=%08lx:ptr=%08lx) "
+ "then(%s/%d:p/v=%08lx/%08lx)\n",
+ regs->eip, address,
+ update_debug_queue[i].file,
+ update_debug_queue[i].line,
+ update_debug_queue[i].ptr,
+ update_debug_queue[i].val);
+ }
+ }
+ }
+#endif
+
+ if ( flush_page_update_queue() != 0 ) return;
+
+ /*
+ * We fault-in kernel-space virtual memory on-demand. The
+ * 'reference' page table is init_mm.pgd.
+ *
+ * NOTE! We MUST NOT take any locks for this case. We may
+ * be in an interrupt or a critical region, and should
+ * only copy the information from the master page table,
+ * nothing more.
+ *
+ * This verifies that the fault happens in kernel space
+ * (error_code & 4) == 0, and that the fault was not a
+ * protection error (error_code & 1) == 0.
+ */
+ if (address >= TASK_SIZE && !(error_code & 5))
+ goto vmalloc_fault;
+
+ mm = tsk->mm;
+ info.si_code = SEGV_MAPERR;
+
+ /*
+ * If we're in an interrupt or have no user
+ * context, we must not take the fault..
+ */
+ if (in_interrupt() || !mm)
+ goto no_context;
+
+ down_read(&mm->mmap_sem);
+
+ vma = find_vma(mm, address);
+ if (!vma)
+ goto bad_area;
+ if (vma->vm_start <= address)
+ goto good_area;
+ if (!(vma->vm_flags & VM_GROWSDOWN))
+ goto bad_area;
+ if (error_code & 4) {
+ /*
+ * accessing the stack below %esp is always a bug.
+ * The "+ 32" is there due to some instructions (like
+ * pusha) doing post-decrement on the stack and that
+ * doesn't show up until later..
+ */
+ if (address + 32 < regs->esp)
+ goto bad_area;
+ }
+ if (expand_stack(vma, address))
+ goto bad_area;
+/*
+ * Ok, we have a good vm_area for this memory access, so
+ * we can handle it..
+ */
+good_area:
+ info.si_code = SEGV_ACCERR;
+ write = 0;
+ switch (error_code & 3) {
+ default: /* 3: write, present */
+ /* fall through */
+ case 2: /* write, not present */
+ if (!(vma->vm_flags & VM_WRITE))
+ goto bad_area;
+ write++;
+ break;
+ case 1: /* read, present */
+ goto bad_area;
+ case 0: /* read, not present */
+ if (!(vma->vm_flags & (VM_READ | VM_EXEC)))
+ goto bad_area;
+ }
+
+ survive:
+ /*
+ * If for any reason at all we couldn't handle the fault,
+ * make sure we exit gracefully rather than endlessly redo
+ * the fault.
+ */
+ switch (handle_mm_fault(mm, vma, address, write)) {
+ case 1:
+ tsk->min_flt++;
+ break;
+ case 2:
+ tsk->maj_flt++;
+ break;
+ case 0:
+ goto do_sigbus;
+ default:
+ goto out_of_memory;
+ }
+
+ up_read(&mm->mmap_sem);
+ return;
+
+/*
+ * Something tried to access memory that isn't in our memory map..
+ * Fix it, but check if it's kernel or user first..
+ */
+bad_area:
+ up_read(&mm->mmap_sem);
+
+ /* User mode accesses just cause a SIGSEGV */
+ if (error_code & 4) {
+ tsk->thread.cr2 = address;
+ tsk->thread.error_code = error_code;
+ tsk->thread.trap_no = 14;
+ info.si_signo = SIGSEGV;
+ info.si_errno = 0;
+ /* info.si_code has been set above */
+ info.si_addr = (void *)address;
+ force_sig_info(SIGSEGV, &info, tsk);
+ return;
+ }
+
+no_context:
+ /* Are we prepared to handle this kernel fault? */
+ if ((fixup = search_exception_table(regs->eip)) != 0) {
+ regs->eip = fixup;
+ return;
+ }
+
+/*
+ * Oops. The kernel tried to access some bad page. We'll have to
+ * terminate things with extreme prejudice.
+ */
+
+ bust_spinlocks(1);
+
+ if (address < PAGE_SIZE)
+ printk(KERN_ALERT "Unable to handle kernel NULL pointer dereference");
+ else
+ printk(KERN_ALERT "Unable to handle kernel paging request");
+ printk(" at virtual address %08lx\n",address);
+ printk(" printing eip:\n");
+ printk("%08lx\n", regs->eip);
+ page = ((unsigned long *) cur_pgd)[address >> 22];
+ printk(KERN_ALERT "*pde=%08lx(%08lx)\n", page, machine_to_phys(page));
+ if (page & 1) {
+ page &= PAGE_MASK;
+ address &= 0x003ff000;
+ page = machine_to_phys(page);
+ page = ((unsigned long *) __va(page))[address >> PAGE_SHIFT];
+ printk(KERN_ALERT "*pte=%08lx(%08lx)\n", page,
+ machine_to_phys(page));
+ }
+ die("Oops", regs, error_code);
+ bust_spinlocks(0);
+ do_exit(SIGKILL);
+
+/*
+ * We ran out of memory, or some other thing happened to us that made
+ * us unable to handle the page fault gracefully.
+ */
+out_of_memory:
+ if (tsk->pid == 1) {
+ yield();
+ goto survive;
+ }
+ up_read(&mm->mmap_sem);
+ printk("VM: killing process %s\n", tsk->comm);
+ if (error_code & 4)
+ do_exit(SIGKILL);
+ goto no_context;
+
+do_sigbus:
+ up_read(&mm->mmap_sem);
+
+ /*
+ * Send a sigbus, regardless of whether we were in kernel
+ * or user mode.
+ */
+ tsk->thread.cr2 = address;
+ tsk->thread.error_code = error_code;
+ tsk->thread.trap_no = 14;
+ info.si_signo = SIGBUS;
+ info.si_errno = 0;
+ info.si_code = BUS_ADRERR;
+ info.si_addr = (void *)address;
+ force_sig_info(SIGBUS, &info, tsk);
+
+ /* Kernel mode? Handle exceptions or die */
+ if (!(error_code & 4))
+ goto no_context;
+ return;
+
+vmalloc_fault:
+ {
+ /*
+ * Synchronize this task's top level page-table
+ * with the 'reference' page table.
+ *
+ * Do _not_ use "tsk" here. We might be inside
+ * an interrupt in the middle of a task switch..
+ */
+ int offset = __pgd_offset(address);
+ pgd_t *pgd, *pgd_k;
+ pmd_t *pmd, *pmd_k;
+ pte_t *pte_k;
+
+ pgd = offset + cur_pgd;
+ pgd_k = init_mm.pgd + offset;
+
+ if (!pgd_present(*pgd_k))
+ goto no_context;
+ set_pgd(pgd, *pgd_k);
+
+ pmd = pmd_offset(pgd, address);
+ pmd_k = pmd_offset(pgd_k, address);
+ if (!pmd_present(*pmd_k))
+ goto no_context;
+ set_pmd(pmd, *pmd_k);
+ XENO_flush_page_update_queue(); /* flush PMD update */
+
+ pte_k = pte_offset(pmd_k, address);
+ if (!pte_present(*pte_k))
+ goto no_context;
+ return;
+ }
+}
--- /dev/null
+
+#include <linux/slab.h>
+#include <linux/shm.h>
+#include <linux/mman.h>
+#include <linux/pagemap.h>
+#include <linux/swap.h>
+#include <linux/swapctl.h>
+#include <linux/smp_lock.h>
+#include <linux/init.h>
+#include <linux/file.h>
+#include <linux/fs.h>
+#include <linux/personality.h>
+
+#include <asm/uaccess.h>
+#include <asm/pgalloc.h>
+
+/*
+static int direct_mapped(unsigned long addr)
+{
+ direct_mmap_node_t * node;
+ struct list_head * curr;
+ struct list_head * direct_list = ¤t->mm->context.direct_list;
+
+ curr = direct_list->next;
+ while(curr != direct_list){
+ node = list_entry(curr, direct_mmap_node_t, list);
+ if(node->addr == addr)
+ break;
+ curr = curr->next;
+ }
+
+ if(curr == direct_list)
+ return 0;
+
+ return 1;
+}
+*/
+/*
+unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr, unsigned long len, unsigned long pgoff, unsigned long flags)
+{
+ struct vm_area_struct *vma;
+
+ if (len > TASK_SIZE)
+ return -ENOMEM;
+
+ if (addr) {
+ addr = PAGE_ALIGN(addr);
+ vma = find_vma(current->mm, addr);
+ if (TASK_SIZE - len >= addr &&
+ (!vma || addr + len <= vma->vm_start))
+ return addr;
+ }
+ addr = PAGE_ALIGN(TASK_UNMAPPED_BASE);
+
+ for (vma = find_vma(current->mm, addr); ; vma = vma->vm_next) {
+ if (TASK_SIZE - len < addr)
+ return -ENOMEM;
+
+ if ((!vma || addr + len <= vma->vm_start) && !direct_mapped(addr))
+ return addr;
+
+ addr = vma->vm_end;
+ }
+}
+*/
+struct list_head *find_direct(struct list_head *list, unsigned long addr)
+{
+ struct list_head * curr;
+ struct list_head * direct_list = ¤t->mm->context.direct_list;
+ direct_mmap_node_t * node;
+
+ for ( curr = direct_list->next; curr != direct_list; curr = curr->next )
+ {
+ node = list_entry(curr, direct_mmap_node_t, list);
+ if ( node->vm_start >= addr ) break;
+ }
+
+ return curr;
+}
+
+unsigned long arch_get_unmapped_area(struct file *filp, unsigned long
+addr, unsigned long len, unsigned long pgoff, unsigned long flags)
+{
+ struct vm_area_struct *vma;
+ direct_mmap_node_t * node;
+ struct list_head * curr;
+ struct list_head * direct_list = ¤t->mm->context.direct_list;
+
+ if (len > TASK_SIZE)
+ return -ENOMEM;
+
+ if ( addr )
+ {
+ addr = PAGE_ALIGN(addr);
+ vma = find_vma(current->mm, addr);
+ curr = find_direct(direct_list, addr);
+ node = list_entry(curr, direct_mmap_node_t, list);
+ if ( (TASK_SIZE - len >= addr) &&
+ (!vma || addr + len <= vma->vm_start) &&
+ ((curr == direct_list) || addr + len <= node->vm_start) )
+ return addr;
+ }
+
+ addr = PAGE_ALIGN(TASK_UNMAPPED_BASE);
+
+
+ /* Find first VMA and direct_map nodes with vm_start > addr */
+ vma = find_vma(current->mm, addr);
+ curr = find_direct(direct_list, addr);
+ node = list_entry(curr, direct_mmap_node_t, list);
+
+ for ( ; ; )
+ {
+ if ( TASK_SIZE - len < addr ) return -ENOMEM;
+
+ if ( vma && ((curr == direct_list) || (vma->vm_start < node->vm_start)))
+ {
+ /* Do we fit before VMA node? */
+ if ( addr + len <= vma->vm_start ) return addr;
+ addr = vma->vm_end;
+ vma = vma->vm_next;
+ }
+ else if ( curr != direct_list )
+ {
+ /* Do we fit before direct_map node? */
+ if ( addr + len <= node->vm_start) return addr;
+ addr = node->vm_end;
+ curr = curr->next;
+ node = list_entry(curr, direct_mmap_node_t, list);
+ }
+ else
+ {
+ /* !vma && curr == direct_list */
+ return addr;
+ }
+ }
+}
--- /dev/null
+/******************************************************************************
+ * xeno/mm/hypervisor.c
+ *
+ * Update page tables via the hypervisor.
+ *
+ * Copyright (c) 2002, K A Fraser
+ */
+
+#include <linux/config.h>
+#include <linux/sched.h>
+#include <asm/hypervisor.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/multicall.h>
+
+/*
+ * This suffices to protect us if we ever move to SMP domains.
+ * Further, it protects us against interrupts. At the very least, this is
+ * required for the network driver which flushes the update queue before
+ * pushing new receive buffers.
+ */
+static spinlock_t update_lock = SPIN_LOCK_UNLOCKED;
+
+#define QUEUE_SIZE 2048
+static page_update_request_t update_queue[QUEUE_SIZE];
+unsigned int pt_update_queue_idx = 0;
+#define idx pt_update_queue_idx
+
+#if PT_UPDATE_DEBUG > 0
+page_update_debug_t update_debug_queue[QUEUE_SIZE] = {{0}};
+#undef queue_l1_entry_update
+#undef queue_l2_entry_update
+static void DEBUG_allow_pt_reads(void)
+{
+ pte_t *pte;
+ page_update_request_t update;
+ int i;
+ for ( i = idx-1; i >= 0; i-- )
+ {
+ pte = update_debug_queue[i].ptep;
+ if ( pte == NULL ) continue;
+ update_debug_queue[i].ptep = NULL;
+ update.ptr = phys_to_machine(__pa(pte));
+ update.val = update_debug_queue[i].pteval;
+ HYPERVISOR_pt_update(&update, 1);
+ }
+}
+static void DEBUG_disallow_pt_read(unsigned long pa)
+{
+ pte_t *pte;
+ pmd_t *pmd;
+ pgd_t *pgd;
+ unsigned long pteval;
+ /*
+ * We may fault because of an already outstanding update.
+ * That's okay -- it'll get fixed up in the fault handler.
+ */
+ page_update_request_t update;
+ unsigned long va = (unsigned long)__va(pa);
+ pgd = pgd_offset_k(va);
+ pmd = pmd_offset(pgd, va);
+ pte = pte_offset(pmd, va);
+ update.ptr = phys_to_machine(__pa(pte));
+ pteval = *(unsigned long *)pte;
+ update.val = pteval & ~_PAGE_PRESENT;
+ HYPERVISOR_pt_update(&update, 1);
+ update_debug_queue[idx].ptep = pte;
+ update_debug_queue[idx].pteval = pteval;
+}
+#endif
+
+#if PT_UPDATE_DEBUG > 1
+#undef queue_pt_switch
+#undef queue_tlb_flush
+#undef queue_invlpg
+#undef queue_pgd_pin
+#undef queue_pgd_unpin
+#undef queue_pte_pin
+#undef queue_pte_unpin
+#endif
+
+
+/*
+ * MULTICALL_flush_page_update_queue:
+ * This is a version of the flush which queues as part of a multicall.
+ */
+void MULTICALL_flush_page_update_queue(void)
+{
+ unsigned long flags;
+ spin_lock_irqsave(&update_lock, flags);
+ if ( idx != 0 )
+ {
+#if PT_UPDATE_DEBUG > 1
+ printk("Flushing %d entries from pt update queue\n", idx);
+#endif
+#if PT_UPDATE_DEBUG > 0
+ DEBUG_allow_pt_reads();
+#endif
+ queue_multicall2(__HYPERVISOR_pt_update, update_queue, idx);
+ idx = 0;
+ }
+ spin_unlock_irqrestore(&update_lock, flags);
+}
+
+static inline void __flush_page_update_queue(void)
+{
+#if PT_UPDATE_DEBUG > 1
+ printk("Flushing %d entries from pt update queue\n", idx);
+#endif
+#if PT_UPDATE_DEBUG > 0
+ DEBUG_allow_pt_reads();
+#endif
+ HYPERVISOR_pt_update(update_queue, idx);
+ idx = 0;
+}
+
+void _flush_page_update_queue(void)
+{
+ unsigned long flags;
+ spin_lock_irqsave(&update_lock, flags);
+ if ( idx != 0 ) __flush_page_update_queue();
+ spin_unlock_irqrestore(&update_lock, flags);
+}
+
+static inline void increment_index(void)
+{
+ idx++;
+ if ( unlikely(idx == QUEUE_SIZE) ) __flush_page_update_queue();
+}
+
+void queue_l1_entry_update(unsigned long ptr, unsigned long val)
+{
+ unsigned long flags;
+ spin_lock_irqsave(&update_lock, flags);
+#if PT_UPDATE_DEBUG > 0
+ DEBUG_disallow_pt_read(ptr);
+#endif
+ update_queue[idx].ptr = phys_to_machine(ptr);
+ update_queue[idx].val = val;
+ increment_index();
+ spin_unlock_irqrestore(&update_lock, flags);
+}
+
+void queue_l2_entry_update(unsigned long ptr, unsigned long val)
+{
+ unsigned long flags;
+ spin_lock_irqsave(&update_lock, flags);
+ update_queue[idx].ptr = phys_to_machine(ptr);
+ update_queue[idx].val = val;
+ increment_index();
+ spin_unlock_irqrestore(&update_lock, flags);
+}
+
+void queue_pt_switch(unsigned long ptr)
+{
+ unsigned long flags;
+ spin_lock_irqsave(&update_lock, flags);
+ update_queue[idx].ptr = phys_to_machine(ptr);
+ update_queue[idx].ptr |= PGREQ_EXTENDED_COMMAND;
+ update_queue[idx].val = PGEXT_NEW_BASEPTR;
+ increment_index();
+ spin_unlock_irqrestore(&update_lock, flags);
+}
+
+void queue_tlb_flush(void)
+{
+ unsigned long flags;
+ spin_lock_irqsave(&update_lock, flags);
+ update_queue[idx].ptr = PGREQ_EXTENDED_COMMAND;
+ update_queue[idx].val = PGEXT_TLB_FLUSH;
+ increment_index();
+ spin_unlock_irqrestore(&update_lock, flags);
+}
+
+void queue_invlpg(unsigned long ptr)
+{
+ unsigned long flags;
+ spin_lock_irqsave(&update_lock, flags);
+ update_queue[idx].ptr = PGREQ_EXTENDED_COMMAND;
+ update_queue[idx].val = ptr & PAGE_MASK;
+ update_queue[idx].val |= PGEXT_INVLPG;
+ increment_index();
+ spin_unlock_irqrestore(&update_lock, flags);
+}
+
+void queue_pgd_pin(unsigned long ptr)
+{
+ unsigned long flags;
+ spin_lock_irqsave(&update_lock, flags);
+ update_queue[idx].ptr = phys_to_machine(ptr);
+ update_queue[idx].ptr |= PGREQ_EXTENDED_COMMAND;
+ update_queue[idx].val = PGEXT_PIN_L2_TABLE;
+ increment_index();
+ spin_unlock_irqrestore(&update_lock, flags);
+}
+
+void queue_pgd_unpin(unsigned long ptr)
+{
+ unsigned long flags;
+ spin_lock_irqsave(&update_lock, flags);
+ update_queue[idx].ptr = phys_to_machine(ptr);
+ update_queue[idx].ptr |= PGREQ_EXTENDED_COMMAND;
+ update_queue[idx].val = PGEXT_UNPIN_TABLE;
+ increment_index();
+ spin_unlock_irqrestore(&update_lock, flags);
+}
+
+void queue_pte_pin(unsigned long ptr)
+{
+ unsigned long flags;
+ spin_lock_irqsave(&update_lock, flags);
+ update_queue[idx].ptr = phys_to_machine(ptr);
+ update_queue[idx].ptr |= PGREQ_EXTENDED_COMMAND;
+ update_queue[idx].val = PGEXT_PIN_L1_TABLE;
+ increment_index();
+ spin_unlock_irqrestore(&update_lock, flags);
+}
+
+void queue_pte_unpin(unsigned long ptr)
+{
+ unsigned long flags;
+ spin_lock_irqsave(&update_lock, flags);
+ update_queue[idx].ptr = phys_to_machine(ptr);
+ update_queue[idx].ptr |= PGREQ_EXTENDED_COMMAND;
+ update_queue[idx].val = PGEXT_UNPIN_TABLE;
+ increment_index();
+ spin_unlock_irqrestore(&update_lock, flags);
+}
+
+void queue_set_ldt(unsigned long ptr, unsigned long len)
+{
+ unsigned long flags;
+ spin_lock_irqsave(&update_lock, flags);
+ update_queue[idx].ptr = PGREQ_EXTENDED_COMMAND | ptr;
+ update_queue[idx].val = PGEXT_SET_LDT | (len << PGEXT_CMD_SHIFT);
+ increment_index();
+ spin_unlock_irqrestore(&update_lock, flags);
+}
--- /dev/null
+/*
+ * linux/arch/i386/mm/init.c
+ *
+ * Copyright (C) 1995 Linus Torvalds
+ *
+ * Support of BIGMEM added by Gerhard Wichert, Siemens AG, July 1999
+ */
+
+#include <linux/config.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/types.h>
+#include <linux/ptrace.h>
+#include <linux/mman.h>
+#include <linux/mm.h>
+#include <linux/swap.h>
+#include <linux/smp.h>
+#include <linux/init.h>
+#ifdef CONFIG_BLK_DEV_INITRD
+#include <linux/blk.h>
+#endif
+#include <linux/highmem.h>
+#include <linux/pagemap.h>
+#include <linux/bootmem.h>
+#include <linux/slab.h>
+
+#include <asm/processor.h>
+#include <asm/system.h>
+#include <asm/uaccess.h>
+#include <asm/pgtable.h>
+#include <asm/pgalloc.h>
+#include <asm/dma.h>
+#include <asm/apic.h>
+#include <asm/tlb.h>
+
+mmu_gather_t mmu_gathers[NR_CPUS];
+unsigned long highstart_pfn, highend_pfn;
+static unsigned long totalram_pages;
+static unsigned long totalhigh_pages;
+
+int do_check_pgt_cache(int low, int high)
+{
+ int freed = 0;
+ if(pgtable_cache_size > high) {
+ do {
+ if (!QUICKLIST_EMPTY(pgd_quicklist)) {
+ free_pgd_slow(get_pgd_fast());
+ freed++;
+ }
+ if (!QUICKLIST_EMPTY(pte_quicklist)) {
+ pte_free_slow(pte_alloc_one_fast(NULL, 0));
+ freed++;
+ }
+ } while(pgtable_cache_size > low);
+ }
+ return freed;
+}
+
+void show_mem(void)
+{
+ int i, total = 0, reserved = 0;
+ int shared = 0, cached = 0;
+ int highmem = 0;
+
+ printk("Mem-info:\n");
+ show_free_areas();
+ printk("Free swap: %6dkB\n",nr_swap_pages<<(PAGE_SHIFT-10));
+ i = max_mapnr;
+ while (i-- > 0) {
+ total++;
+ if (PageHighMem(mem_map+i))
+ highmem++;
+ if (PageReserved(mem_map+i))
+ reserved++;
+ else if (PageSwapCache(mem_map+i))
+ cached++;
+ else if (page_count(mem_map+i))
+ shared += page_count(mem_map+i) - 1;
+ }
+ printk("%d pages of RAM\n", total);
+ printk("%d pages of HIGHMEM\n",highmem);
+ printk("%d reserved pages\n",reserved);
+ printk("%d pages shared\n",shared);
+ printk("%d pages swap cached\n",cached);
+ printk("%ld pages in page table cache\n",pgtable_cache_size);
+ show_buffers();
+}
+
+/* References to section boundaries */
+
+extern char _text, _etext, _edata, __bss_start, _end;
+extern char __init_begin, __init_end;
+
+static inline void set_pte_phys (unsigned long vaddr,
+ unsigned long phys, pgprot_t flags)
+{
+ pgprot_t prot;
+ pgd_t *pgd;
+ pmd_t *pmd;
+ pte_t *pte;
+
+ pgd = init_mm.pgd + __pgd_offset(vaddr);
+ if (pgd_none(*pgd)) {
+ printk("PAE BUG #00!\n");
+ return;
+ }
+ pmd = pmd_offset(pgd, vaddr);
+ if (pmd_none(*pmd)) {
+ printk("PAE BUG #01!\n");
+ return;
+ }
+ pte = pte_offset(pmd, vaddr);
+#if 0 // XXX Xen ?????
+ /* <phys,flags> stored as-is, to permit clearing entries */
+ set_pte(pte, mk_pte_phys(phys, flags));
+#endif
+ if (pte_val(*pte))
+ pte_ERROR(*pte);
+
+ pgprot_val(prot) = pgprot_val(PAGE_KERNEL) | pgprot_val(flags);
+
+ /* We queue directly, avoiding hidden phys->machine translation. */
+ queue_l1_entry_update(__pa(pte), phys | pgprot_val(prot));
+
+ /*
+ * It's enough to flush this one mapping.
+ * (PGE mappings get flushed as well)
+ */
+ __flush_tlb_one(vaddr);
+}
+
+void __set_fixmap (enum fixed_addresses idx, unsigned long phys,
+ pgprot_t flags)
+{
+ unsigned long address = __fix_to_virt(idx);
+
+ if (idx >= __end_of_fixed_addresses) {
+ printk("Invalid __set_fixmap\n");
+ return;
+ }
+ set_pte_phys(address, phys, flags);
+}
+
+static void __init fixrange_init (unsigned long start,
+ unsigned long end, pgd_t *pgd_base)
+{
+ pgd_t *pgd, *kpgd;
+ pmd_t *pmd, *kpmd;
+ pte_t *pte, *kpte;
+ int i, j;
+ unsigned long vaddr;
+
+ vaddr = start;
+ i = __pgd_offset(vaddr);
+ j = __pmd_offset(vaddr);
+ pgd = pgd_base + i;
+
+ for ( ; (i < PTRS_PER_PGD) && (vaddr != end); pgd++, i++) {
+#if CONFIG_X86_PAE
+ if (pgd_none(*pgd)) {
+ pmd = (pmd_t *) alloc_bootmem_low_pages(PAGE_SIZE);
+ set_pgd(pgd, __pgd(__pa(pmd) + 0x1));
+ if (pmd != pmd_offset(pgd, 0))
+ printk("PAE BUG #02!\n");
+ }
+ pmd = pmd_offset(pgd, vaddr);
+#else
+ pmd = (pmd_t *)pgd;
+#endif
+ for (; (j < PTRS_PER_PMD) && (vaddr != end); pmd++, j++) {
+ if (pmd_none(*pmd)) {
+ pte = (pte_t *) alloc_bootmem_low_pages(PAGE_SIZE);
+ clear_page(pte);
+ kpgd = pgd_offset_k((unsigned long)pte);
+ kpmd = pmd_offset(kpgd, (unsigned long)pte);
+ kpte = pte_offset(kpmd, (unsigned long)pte);
+ queue_l1_entry_update(__pa(kpte),
+ (*(unsigned long *)kpte)&~_PAGE_RW);
+
+ set_pmd(pmd, __pmd(_KERNPG_TABLE + __pa(pte)));
+
+ // XXX Xen below reqd ?
+ //if (pte != pte_offset(pmd, 0))
+ // BUG();
+ }
+ vaddr += PMD_SIZE;
+ }
+ j = 0;
+ }
+
+ XENO_flush_page_update_queue();
+}
+
+
+static void __init zone_sizes_init(void)
+{
+ unsigned long zones_size[MAX_NR_ZONES] = {0, 0, 0};
+ unsigned int max_dma, high, low;
+
+ max_dma = virt_to_phys((char *)MAX_DMA_ADDRESS) >> PAGE_SHIFT;
+ low = max_low_pfn;
+ high = highend_pfn;
+
+ if (low < max_dma)
+ zones_size[ZONE_DMA] = low;
+ else {
+ zones_size[ZONE_DMA] = max_dma;
+ zones_size[ZONE_NORMAL] = low - max_dma;
+#ifdef CONFIG_HIGHMEM
+ zones_size[ZONE_HIGHMEM] = high - low;
+#endif
+ }
+ free_area_init(zones_size);
+}
+
+/*
+ * paging_init() sets up the page tables - note that the first 8MB are
+ * already mapped by head.S.
+ *
+ * This routines also unmaps the page at virtual kernel address 0, so
+ * that we can trap those pesky NULL-reference errors in the kernel.
+ */
+void __init paging_init(void)
+{
+ unsigned long vaddr;
+
+ zone_sizes_init();
+
+ /*
+ * Fixed mappings, only the page table structure has to be created -
+ * mappings will be set by set_fixmap():
+ */
+ vaddr = __fix_to_virt(__end_of_fixed_addresses - 1) & PMD_MASK;
+ fixrange_init(vaddr, HYPERVISOR_VIRT_START, init_mm.pgd);
+
+ /* Cheesy: this can probably be moved to the blkdev driver. */
+ set_fixmap(FIX_BLKRING_BASE, start_info.blk_ring);
+
+#ifdef CONFIG_HIGHMEM
+#error
+ kmap_init();
+#endif
+}
+
+static inline int page_is_ram (unsigned long pagenr)
+{
+ return 1;
+}
+
+#ifdef CONFIG_HIGHMEM
+void __init one_highpage_init(struct page *page, int pfn, int bad_ppro)
+{
+ if (!page_is_ram(pfn)) {
+ SetPageReserved(page);
+ return;
+ }
+
+ if (bad_ppro && page_kills_ppro(pfn)) {
+ SetPageReserved(page);
+ return;
+ }
+
+ ClearPageReserved(page);
+ set_bit(PG_highmem, &page->flags);
+ atomic_set(&page->count, 1);
+ __free_page(page);
+ totalhigh_pages++;
+}
+#endif /* CONFIG_HIGHMEM */
+
+static void __init set_max_mapnr_init(void)
+{
+#ifdef CONFIG_HIGHMEM
+ highmem_start_page = mem_map + highstart_pfn;
+ max_mapnr = num_physpages = highend_pfn;
+ num_mappedpages = max_low_pfn;
+#else
+ max_mapnr = num_mappedpages = num_physpages = max_low_pfn;
+#endif
+}
+
+static int __init free_pages_init(void)
+{
+ int bad_ppro, reservedpages, pfn;
+
+ /* this will put all low memory onto the freelists */
+ totalram_pages += free_all_bootmem();
+
+ reservedpages = 0;
+ for (pfn = 0; pfn < max_low_pfn; pfn++) {
+ /*
+ * Only count reserved RAM pages
+ */
+ if (page_is_ram(pfn) && PageReserved(mem_map+pfn))
+ reservedpages++;
+ }
+#ifdef CONFIG_HIGHMEM
+ for (pfn = highend_pfn-1; pfn >= highstart_pfn; pfn--)
+ one_highpage_init((struct page *) (mem_map + pfn), pfn, bad_ppro);
+ totalram_pages += totalhigh_pages;
+#endif
+ return reservedpages;
+}
+
+void __init mem_init(void)
+{
+ int codesize, reservedpages, datasize, initsize;
+
+ if (!mem_map)
+ BUG();
+
+ set_max_mapnr_init();
+
+ high_memory = (void *) __va(max_low_pfn * PAGE_SIZE);
+
+ /* clear the zero-page */
+ memset(empty_zero_page, 0, PAGE_SIZE);
+
+ reservedpages = free_pages_init();
+
+ codesize = (unsigned long) &_etext - (unsigned long) &_text;
+ datasize = (unsigned long) &_edata - (unsigned long) &_etext;
+ initsize = (unsigned long) &__init_end - (unsigned long) &__init_begin;
+
+ printk(KERN_INFO "Memory: %luk/%luk available (%dk kernel code, %dk reserved, %dk data, %dk init, %ldk highmem)\n",
+ (unsigned long) nr_free_pages() << (PAGE_SHIFT-10),
+ max_mapnr << (PAGE_SHIFT-10),
+ codesize >> 10,
+ reservedpages << (PAGE_SHIFT-10),
+ datasize >> 10,
+ initsize >> 10,
+ (unsigned long) (totalhigh_pages << (PAGE_SHIFT-10))
+ );
+
+ boot_cpu_data.wp_works_ok = 1;
+}
+
+void free_initmem(void)
+{
+ unsigned long addr;
+
+ addr = (unsigned long)(&__init_begin);
+ for (; addr < (unsigned long)(&__init_end); addr += PAGE_SIZE) {
+ ClearPageReserved(virt_to_page(addr));
+ set_page_count(virt_to_page(addr), 1);
+ free_page(addr);
+ totalram_pages++;
+ }
+ printk (KERN_INFO "Freeing unused kernel memory: %dk freed\n", (&__init_end - &__init_begin) >> 10);
+}
+
+#ifdef CONFIG_BLK_DEV_INITRD
+void free_initrd_mem(unsigned long start, unsigned long end)
+{
+ if (start < end)
+ printk (KERN_INFO "Freeing initrd memory: %ldk freed\n", (end - start) >> 10);
+ for (; start < end; start += PAGE_SIZE) {
+ ClearPageReserved(virt_to_page(start));
+ set_page_count(virt_to_page(start), 1);
+ free_page(start);
+ totalram_pages++;
+ }
+}
+#endif
+
+void si_meminfo(struct sysinfo *val)
+{
+ val->totalram = totalram_pages;
+ val->sharedram = 0;
+ val->freeram = nr_free_pages();
+ val->bufferram = atomic_read(&buffermem_pages);
+ val->totalhigh = totalhigh_pages;
+ val->freehigh = nr_free_highpages();
+ val->mem_unit = PAGE_SIZE;
+ return;
+}
+
+#if defined(CONFIG_X86_PAE)
+struct kmem_cache_s *pae_pgd_cachep;
+void __init pgtable_cache_init(void)
+{
+ /*
+ * PAE pgds must be 16-byte aligned:
+ */
+ pae_pgd_cachep = kmem_cache_create("pae_pgd", 32, 0,
+ SLAB_HWCACHE_ALIGN | SLAB_MUST_HWCACHE_ALIGN, NULL, NULL);
+ if (!pae_pgd_cachep)
+ panic("init_pae(): Cannot alloc pae_pgd SLAB cache");
+}
+#endif /* CONFIG_X86_PAE */
--- /dev/null
+
+#include <linux/slab.h>
+#include <linux/list.h>
+
+int init_new_context(struct task_struct *tsk, struct mm_struct *mm)
+{
+ INIT_LIST_HEAD(&mm->context.direct_list);
+ return 0;
+}
+
+/* just free all elements of list identifying directly mapped areas */
+void destroy_context(struct mm_struct *mm)
+{
+ direct_mmap_node_t * node;
+ struct list_head * curr;
+ struct list_head * direct_list = &mm->context.direct_list;
+
+ curr = direct_list->next;
+ while(curr != direct_list){
+ node = list_entry(curr, direct_mmap_node_t, list);
+ curr = curr->next;
+ list_del(&node->list);
+ kfree(node);
+ }
+
+}
--- /dev/null
+/* ld script to make i386 Linux kernel
+ * Written by Martin Mares <mj@atrey.karlin.mff.cuni.cz>;
+ */
+OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386")
+OUTPUT_ARCH(i386)
+ENTRY(_start)
+SECTIONS
+{
+ . = 0xC0000000 + 0x000000;
+ _text = .; /* Text and read-only data */
+ .text : {
+ *(.text)
+ *(.fixup)
+ *(.gnu.warning)
+ } = 0x9090
+
+ _etext = .; /* End of text section */
+
+ .rodata : { *(.rodata) *(.rodata.*) }
+ .kstrtab : { *(.kstrtab) }
+
+ . = ALIGN(16); /* Exception table */
+ __start___ex_table = .;
+ __ex_table : { *(__ex_table) }
+ __stop___ex_table = .;
+
+ __start___ksymtab = .; /* Kernel symbol table */
+ __ksymtab : { *(__ksymtab) }
+ __stop___ksymtab = .;
+
+ .data : { /* Data */
+ *(.data)
+ CONSTRUCTORS
+ }
+
+ _edata = .; /* End of data section */
+
+ . = ALIGN(8192); /* init_task */
+ .data.init_task : { *(.data.init_task) }
+
+ . = ALIGN(4096); /* Init code and data */
+ __init_begin = .;
+ .text.init : { *(.text.init) }
+ .data.init : { *(.data.init) }
+ . = ALIGN(16);
+ __setup_start = .;
+ .setup.init : { *(.setup.init) }
+ __setup_end = .;
+ __initcall_start = .;
+ .initcall.init : { *(.initcall.init) }
+ __initcall_end = .;
+ . = ALIGN(4096);
+ __init_end = .;
+
+ . = ALIGN(4096);
+ .data.page_aligned : { *(.data.idt) }
+
+ . = ALIGN(32);
+ .data.cacheline_aligned : { *(.data.cacheline_aligned) }
+
+ __bss_start = .; /* BSS */
+ .bss : {
+ *(.bss)
+ }
+ _end = . ;
+
+ /* Sections to be discarded */
+ /DISCARD/ : {
+ *(.text.exit)
+ *(.data.exit)
+ *(.exitcall.exit)
+ }
+
+ /* Stabs debugging sections. */
+ .stab 0 : { *(.stab) }
+ .stabstr 0 : { *(.stabstr) }
+ .stab.excl 0 : { *(.stab.excl) }
+ .stab.exclstr 0 : { *(.stab.exclstr) }
+ .stab.index 0 : { *(.stab.index) }
+ .stab.indexstr 0 : { *(.stab.indexstr) }
+ .comment 0 : { *(.comment) }
+}
--- /dev/null
+/*
+ * Code extracted from
+ * linux/kernel/hd.c
+ *
+ * Copyright (C) 1991-1998 Linus Torvalds
+ *
+ * devfs support - jj, rgooch, 980122
+ *
+ * Moved partition checking code to fs/partitions* - Russell King
+ * (linux@arm.uk.linux.org)
+ */
+
+/*
+ * TODO: rip out the remaining init crap from this file --hch
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/genhd.h>
+#include <linux/kernel.h>
+#include <linux/blk.h>
+#include <linux/init.h>
+#include <linux/spinlock.h>
+#include <linux/seq_file.h>
+
+
+/*
+ * Global kernel list of partitioning information.
+ *
+ * XXX: you should _never_ access this directly.
+ * the only reason this is exported is source compatiblity.
+ */
+/*static*/ struct gendisk *gendisk_head;
+static struct gendisk *gendisk_array[MAX_BLKDEV];
+static rwlock_t gendisk_lock = RW_LOCK_UNLOCKED;
+
+EXPORT_SYMBOL(gendisk_head);
+
+
+/**
+ * add_gendisk - add partitioning information to kernel list
+ * @gp: per-device partitioning information
+ *
+ * This function registers the partitioning information in @gp
+ * with the kernel.
+ */
+void
+add_gendisk(struct gendisk *gp)
+{
+ struct gendisk *sgp;
+
+ write_lock(&gendisk_lock);
+
+ /*
+ * In 2.5 this will go away. Fix the drivers who rely on
+ * old behaviour.
+ */
+
+ for (sgp = gendisk_head; sgp; sgp = sgp->next)
+ {
+ if (sgp == gp)
+ {
+// printk(KERN_ERR "add_gendisk: device major %d is buggy and added a live gendisk!\n",
+// sgp->major)
+ goto out;
+ }
+ }
+ gendisk_array[gp->major] = gp;
+ gp->next = gendisk_head;
+ gendisk_head = gp;
+out:
+ write_unlock(&gendisk_lock);
+}
+
+EXPORT_SYMBOL(add_gendisk);
+
+
+/**
+ * del_gendisk - remove partitioning information from kernel list
+ * @gp: per-device partitioning information
+ *
+ * This function unregisters the partitioning information in @gp
+ * with the kernel.
+ */
+void
+del_gendisk(struct gendisk *gp)
+{
+ struct gendisk **gpp;
+
+ write_lock(&gendisk_lock);
+ gendisk_array[gp->major] = NULL;
+ for (gpp = &gendisk_head; *gpp; gpp = &((*gpp)->next))
+ if (*gpp == gp)
+ break;
+ if (*gpp)
+ *gpp = (*gpp)->next;
+ write_unlock(&gendisk_lock);
+}
+
+EXPORT_SYMBOL(del_gendisk);
+
+
+/**
+ * get_gendisk - get partitioning information for a given device
+ * @dev: device to get partitioning information for
+ *
+ * This function gets the structure containing partitioning
+ * information for the given device @dev.
+ */
+struct gendisk *
+get_gendisk(kdev_t dev)
+{
+ struct gendisk *gp = NULL;
+ int maj = MAJOR(dev);
+
+ read_lock(&gendisk_lock);
+ if ((gp = gendisk_array[maj]))
+ goto out;
+
+ /* This is needed for early 2.4 source compatiblity. --hch */
+ for (gp = gendisk_head; gp; gp = gp->next)
+ if (gp->major == maj)
+ break;
+out:
+ read_unlock(&gendisk_lock);
+ return gp;
+}
+
+EXPORT_SYMBOL(get_gendisk);
+
+
+/**
+ * walk_gendisk - issue a command for every registered gendisk
+ * @walk: user-specified callback
+ * @data: opaque data for the callback
+ *
+ * This function walks through the gendisk chain and calls back
+ * into @walk for every element.
+ */
+int
+walk_gendisk(int (*walk)(struct gendisk *, void *), void *data)
+{
+ struct gendisk *gp;
+ int error = 0;
+
+ read_lock(&gendisk_lock);
+ for (gp = gendisk_head; gp; gp = gp->next)
+ if ((error = walk(gp, data)))
+ break;
+ read_unlock(&gendisk_lock);
+
+ return error;
+}
+
+#ifdef CONFIG_PROC_FS
+/* iterator */
+static void *part_start(struct seq_file *s, loff_t *ppos)
+{
+ struct gendisk *gp;
+ loff_t pos = *ppos;
+
+ read_lock(&gendisk_lock);
+ for (gp = gendisk_head; gp; gp = gp->next)
+ if (!pos--)
+ return gp;
+ return NULL;
+}
+
+static void *part_next(struct seq_file *s, void *v, loff_t *pos)
+{
+ ++*pos;
+ return ((struct gendisk *)v)->next;
+}
+
+static void part_stop(struct seq_file *s, void *v)
+{
+ read_unlock(&gendisk_lock);
+}
+
+static int part_show(struct seq_file *s, void *v)
+{
+ struct gendisk *gp = v;
+ char buf[64];
+ int n;
+
+ if (gp == gendisk_head) {
+ seq_puts(s, "major minor #blocks start_sect nr_sects name"
+#ifdef CONFIG_BLK_STATS
+ " rio rmerge rsect ruse wio wmerge "
+ "wsect wuse running use aveq"
+#endif
+ "\n\n");
+ }
+
+ /* show the full disk and all non-0 size partitions of it */
+ for (n = 0; n < (gp->nr_real << gp->minor_shift); n++) {
+ if (gp->part[n].nr_sects) {
+#ifdef CONFIG_BLK_STATS
+ struct hd_struct *hd = &gp->part[n];
+
+ disk_round_stats(hd);
+ seq_printf(s, "%4d %4d %10d %10ld %s "
+ "%d %d %d %d %d %d %d %d %d %d %d\n",
+ gp->major, n, gp->sizes[n],
+ gp->part[n].start_sect,
+ gp->part[n].nr_sects,
+ disk_name(gp, n, buf),
+ hd->rd_ios, hd->rd_merges,
+#define MSEC(x) ((x) * 1000 / HZ)
+ hd->rd_sectors, MSEC(hd->rd_ticks),
+ hd->wr_ios, hd->wr_merges,
+ hd->wr_sectors, MSEC(hd->wr_ticks),
+ hd->ios_in_flight, MSEC(hd->io_ticks),
+ MSEC(hd->aveq));
+#else
+ seq_printf(s, "%4d %4d %10d %10ld %10ld %s\n",
+ gp->major, n, gp->sizes[n],
+ gp->part[n].start_sect,
+ gp->part[n].nr_sects,
+ disk_name(gp, n, buf));
+#endif /* CONFIG_BLK_STATS */
+ }
+ }
+
+ return 0;
+}
+
+struct seq_operations partitions_op = {
+ .start = part_start,
+ .next = part_next,
+ .stop = part_stop,
+ .show = part_show,
+};
+#endif
+
+extern int blk_dev_init(void);
+extern int net_dev_init(void);
+extern void console_map_init(void);
+extern int atmdev_init(void);
+
+int __init device_init(void)
+{
+ blk_dev_init();
+ sti();
+#ifdef CONFIG_NET
+ net_dev_init();
+#endif
+#ifdef CONFIG_ATM
+ (void) atmdev_init();
+#endif
+#ifdef CONFIG_VT
+ console_map_init();
+#endif
+ return 0;
+}
+
+__initcall(device_init);
--- /dev/null
+/*
+ * linux/drivers/block/ll_rw_blk.c
+ *
+ * Copyright (C) 1991, 1992 Linus Torvalds
+ * Copyright (C) 1994, Karl Keyte: Added support for disk statistics
+ * Elevator latency, (C) 2000 Andrea Arcangeli <andrea@suse.de> SuSE
+ * Queue request tables / lock, selectable elevator, Jens Axboe <axboe@suse.de>
+ * kernel-doc documentation started by NeilBrown <neilb@cse.unsw.edu.au> - July2000
+ */
+
+/*
+ * This handles all read/write requests to block devices
+ */
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/kernel_stat.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/config.h>
+#include <linux/locks.h>
+#include <linux/mm.h>
+#include <linux/swap.h>
+#include <linux/init.h>
+#include <linux/smp_lock.h>
+#include <linux/completion.h>
+#include <linux/bootmem.h>
+
+#include <asm/system.h>
+#include <asm/io.h>
+#include <linux/blk.h>
+#include <linux/highmem.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+
+/*
+ * MAC Floppy IWM hooks
+ */
+
+#ifdef CONFIG_MAC_FLOPPY_IWM
+extern int mac_floppy_init(void);
+#endif
+
+/*
+ * For the allocated request tables
+ */
+static kmem_cache_t *request_cachep;
+
+/*
+ * The "disk" task queue is used to start the actual requests
+ * after a plug
+ */
+DECLARE_TASK_QUEUE(tq_disk);
+
+/*
+ * Protect the request list against multiple users..
+ *
+ * With this spinlock the Linux block IO subsystem is 100% SMP threaded
+ * from the IRQ event side, and almost 100% SMP threaded from the syscall
+ * side (we still have protect against block device array operations, and
+ * the do_request() side is casually still unsafe. The kernel lock protects
+ * this part currently.).
+ *
+ * there is a fair chance that things will work just OK if these functions
+ * are called with no global kernel lock held ...
+ */
+spinlock_t io_request_lock = SPIN_LOCK_UNLOCKED;
+
+/* This specifies how many sectors to read ahead on the disk. */
+
+int read_ahead[MAX_BLKDEV];
+
+/* blk_dev_struct is:
+ * *request_fn
+ * *current_request
+ */
+struct blk_dev_struct blk_dev[MAX_BLKDEV]; /* initialized by blk_dev_init() */
+
+/*
+ * blk_size contains the size of all block-devices in units of 1024 byte
+ * sectors:
+ *
+ * blk_size[MAJOR][MINOR]
+ *
+ * if (!blk_size[MAJOR]) then no minor size checking is done.
+ */
+int * blk_size[MAX_BLKDEV];
+
+/*
+ * blksize_size contains the size of all block-devices:
+ *
+ * blksize_size[MAJOR][MINOR]
+ *
+ * if (!blksize_size[MAJOR]) then 1024 bytes is assumed.
+ */
+int * blksize_size[MAX_BLKDEV];
+
+/*
+ * hardsect_size contains the size of the hardware sector of a device.
+ *
+ * hardsect_size[MAJOR][MINOR]
+ *
+ * if (!hardsect_size[MAJOR])
+ * then 512 bytes is assumed.
+ * else
+ * sector_size is hardsect_size[MAJOR][MINOR]
+ * This is currently set by some scsi devices and read by the msdos fs driver.
+ * Other uses may appear later.
+ */
+int * hardsect_size[MAX_BLKDEV];
+
+/*
+ * The following tunes the read-ahead algorithm in mm/filemap.c
+ */
+int * max_readahead[MAX_BLKDEV];
+
+/*
+ * Max number of sectors per request
+ */
+int * max_sectors[MAX_BLKDEV];
+
+unsigned long blk_max_low_pfn, blk_max_pfn;
+int blk_nohighio = 0;
+
+static inline int get_max_sectors(kdev_t dev)
+{
+ if (!max_sectors[MAJOR(dev)])
+ return MAX_SECTORS;
+ return max_sectors[MAJOR(dev)][MINOR(dev)];
+}
+
+inline request_queue_t *blk_get_queue(kdev_t dev)
+{
+ struct blk_dev_struct *bdev = blk_dev + MAJOR(dev);
+
+ if (bdev->queue)
+ return bdev->queue(dev);
+ else
+ return &blk_dev[MAJOR(dev)].request_queue;
+}
+
+static int __blk_cleanup_queue(struct request_list *list)
+{
+ struct list_head *head = &list->free;
+ struct request *rq;
+ int i = 0;
+
+ while (!list_empty(head)) {
+ rq = list_entry(head->next, struct request, queue);
+ list_del(&rq->queue);
+ kmem_cache_free(request_cachep, rq);
+ i++;
+ };
+
+ if (i != list->count)
+ printk("request list leak!\n");
+
+ list->count = 0;
+ return i;
+}
+
+/**
+ * blk_cleanup_queue: - release a &request_queue_t when it is no longer needed
+ * @q: the request queue to be released
+ *
+ * Description:
+ * blk_cleanup_queue is the pair to blk_init_queue(). It should
+ * be called when a request queue is being released; typically
+ * when a block device is being de-registered. Currently, its
+ * primary task it to free all the &struct request structures that
+ * were allocated to the queue.
+ * Caveat:
+ * Hopefully the low level driver will have finished any
+ * outstanding requests first...
+ **/
+void blk_cleanup_queue(request_queue_t * q)
+{
+ int count = q->nr_requests;
+
+ count -= __blk_cleanup_queue(&q->rq[READ]);
+ count -= __blk_cleanup_queue(&q->rq[WRITE]);
+
+ if (count)
+ printk("blk_cleanup_queue: leaked requests (%d)\n", count);
+
+ memset(q, 0, sizeof(*q));
+}
+
+/**
+ * blk_queue_headactive - indicate whether head of request queue may be active
+ * @q: The queue which this applies to.
+ * @active: A flag indication where the head of the queue is active.
+ *
+ * Description:
+ * The driver for a block device may choose to leave the currently active
+ * request on the request queue, removing it only when it has completed.
+ * The queue handling routines assume this by default for safety reasons
+ * and will not involve the head of the request queue in any merging or
+ * reordering of requests when the queue is unplugged (and thus may be
+ * working on this particular request).
+ *
+ * If a driver removes requests from the queue before processing them, then
+ * it may indicate that it does so, there by allowing the head of the queue
+ * to be involved in merging and reordering. This is done be calling
+ * blk_queue_headactive() with an @active flag of %0.
+ *
+ * If a driver processes several requests at once, it must remove them (or
+ * at least all but one of them) from the request queue.
+ *
+ * When a queue is plugged the head will be assumed to be inactive.
+ **/
+
+void blk_queue_headactive(request_queue_t * q, int active)
+{
+ q->head_active = active;
+}
+
+/**
+ * blk_queue_make_request - define an alternate make_request function for a device
+ * @q: the request queue for the device to be affected
+ * @mfn: the alternate make_request function
+ *
+ * Description:
+ * The normal way for &struct buffer_heads to be passed to a device
+ * driver is for them to be collected into requests on a request
+ * queue, and then to allow the device driver to select requests
+ * off that queue when it is ready. This works well for many block
+ * devices. However some block devices (typically virtual devices
+ * such as md or lvm) do not benefit from the processing on the
+ * request queue, and are served best by having the requests passed
+ * directly to them. This can be achieved by providing a function
+ * to blk_queue_make_request().
+ *
+ * Caveat:
+ * The driver that does this *must* be able to deal appropriately
+ * with buffers in "highmemory", either by calling bh_kmap() to get
+ * a kernel mapping, to by calling create_bounce() to create a
+ * buffer in normal memory.
+ **/
+
+void blk_queue_make_request(request_queue_t * q, make_request_fn * mfn)
+{
+ q->make_request_fn = mfn;
+}
+
+/**
+ * blk_queue_bounce_limit - set bounce buffer limit for queue
+ * @q: the request queue for the device
+ * @dma_addr: bus address limit
+ *
+ * Description:
+ * Different hardware can have different requirements as to what pages
+ * it can do I/O directly to. A low level driver can call
+ * blk_queue_bounce_limit to have lower memory pages allocated as bounce
+ * buffers for doing I/O to pages residing above @page. By default
+ * the block layer sets this to the highest numbered "low" memory page.
+ **/
+void blk_queue_bounce_limit(request_queue_t *q, u64 dma_addr)
+{
+ unsigned long bounce_pfn = dma_addr >> PAGE_SHIFT;
+ unsigned long mb = dma_addr >> 20;
+ static request_queue_t *old_q;
+
+ /*
+ * keep this for debugging for now...
+ */
+ if (dma_addr != BLK_BOUNCE_HIGH && q != old_q) {
+ old_q = q;
+ printk("blk: queue %p, ", q);
+ if (dma_addr == BLK_BOUNCE_ANY)
+ printk("no I/O memory limit\n");
+ else
+ printk("I/O limit %luMb (mask 0x%Lx)\n", mb,
+ (long long) dma_addr);
+ }
+
+ q->bounce_pfn = bounce_pfn;
+}
+
+
+/*
+ * can we merge the two segments, or do we need to start a new one?
+ */
+inline int blk_seg_merge_ok(struct buffer_head *bh, struct buffer_head *nxt)
+{
+ /*
+ * if bh and nxt are contigous and don't cross a 4g boundary, it's ok
+ */
+ if (BH_CONTIG(bh, nxt) && BH_PHYS_4G(bh, nxt))
+ return 1;
+
+ return 0;
+}
+
+static inline int ll_new_segment(request_queue_t *q, struct request *req, int max_segments)
+{
+ if (req->nr_segments < max_segments) {
+ req->nr_segments++;
+ return 1;
+ }
+ return 0;
+}
+
+static int ll_back_merge_fn(request_queue_t *q, struct request *req,
+ struct buffer_head *bh, int max_segments)
+{
+ if (blk_seg_merge_ok(req->bhtail, bh))
+ return 1;
+
+ return ll_new_segment(q, req, max_segments);
+}
+
+static int ll_front_merge_fn(request_queue_t *q, struct request *req,
+ struct buffer_head *bh, int max_segments)
+{
+ if (blk_seg_merge_ok(bh, req->bh))
+ return 1;
+
+ return ll_new_segment(q, req, max_segments);
+}
+
+static int ll_merge_requests_fn(request_queue_t *q, struct request *req,
+ struct request *next, int max_segments)
+{
+ int total_segments = req->nr_segments + next->nr_segments;
+
+ if (blk_seg_merge_ok(req->bhtail, next->bh))
+ total_segments--;
+
+ if (total_segments > max_segments)
+ return 0;
+
+ req->nr_segments = total_segments;
+ return 1;
+}
+
+/*
+ * "plug" the device if there are no outstanding requests: this will
+ * force the transfer to start only after we have put all the requests
+ * on the list.
+ *
+ * This is called with interrupts off and no requests on the queue.
+ * (and with the request spinlock acquired)
+ */
+static void generic_plug_device(request_queue_t *q, kdev_t dev)
+{
+ /*
+ * no need to replug device
+ */
+ if (!list_empty(&q->queue_head) || q->plugged)
+ return;
+
+ q->plugged = 1;
+ queue_task(&q->plug_tq, &tq_disk);
+}
+
+/*
+ * remove the plug and let it rip..
+ */
+static inline void __generic_unplug_device(request_queue_t *q)
+{
+ if (q->plugged) {
+ q->plugged = 0;
+ if (!list_empty(&q->queue_head))
+ q->request_fn(q);
+ }
+}
+
+void generic_unplug_device(void *data)
+{
+ request_queue_t *q = (request_queue_t *) data;
+ unsigned long flags;
+
+ spin_lock_irqsave(&io_request_lock, flags);
+ __generic_unplug_device(q);
+ spin_unlock_irqrestore(&io_request_lock, flags);
+}
+
+/** blk_grow_request_list
+ * @q: The &request_queue_t
+ * @nr_requests: how many requests are desired
+ *
+ * More free requests are added to the queue's free lists, bringing
+ * the total number of requests to @nr_requests.
+ *
+ * The requests are added equally to the request queue's read
+ * and write freelists.
+ *
+ * This function can sleep.
+ *
+ * Returns the (new) number of requests which the queue has available.
+ */
+int blk_grow_request_list(request_queue_t *q, int nr_requests)
+{
+ unsigned long flags;
+ /* Several broken drivers assume that this function doesn't sleep,
+ * this causes system hangs during boot.
+ * As a temporary fix, make the function non-blocking.
+ */
+ spin_lock_irqsave(&io_request_lock, flags);
+ while (q->nr_requests < nr_requests) {
+ struct request *rq;
+ int rw;
+
+ rq = kmem_cache_alloc(request_cachep, SLAB_ATOMIC);
+ if (rq == NULL)
+ break;
+ memset(rq, 0, sizeof(*rq));
+ rq->rq_status = RQ_INACTIVE;
+ rw = q->nr_requests & 1;
+ list_add(&rq->queue, &q->rq[rw].free);
+ q->rq[rw].count++;
+ q->nr_requests++;
+ }
+ q->batch_requests = q->nr_requests / 4;
+ if (q->batch_requests > 32)
+ q->batch_requests = 32;
+ spin_unlock_irqrestore(&io_request_lock, flags);
+ return q->nr_requests;
+}
+
+static void blk_init_free_list(request_queue_t *q)
+{
+ struct sysinfo si;
+ int megs; /* Total memory, in megabytes */
+ int nr_requests;
+
+ INIT_LIST_HEAD(&q->rq[READ].free);
+ INIT_LIST_HEAD(&q->rq[WRITE].free);
+ q->rq[READ].count = 0;
+ q->rq[WRITE].count = 0;
+ q->nr_requests = 0;
+
+ si_meminfo(&si);
+ megs = si.totalram >> (20 - PAGE_SHIFT);
+ nr_requests = 128;
+ if (megs < 32)
+ nr_requests /= 2;
+ blk_grow_request_list(q, nr_requests);
+
+ init_waitqueue_head(&q->wait_for_requests[0]);
+ init_waitqueue_head(&q->wait_for_requests[1]);
+ spin_lock_init(&q->queue_lock);
+}
+
+static int __make_request(request_queue_t * q, int rw, struct buffer_head * bh);
+
+/**
+ * blk_init_queue - prepare a request queue for use with a block device
+ * @q: The &request_queue_t to be initialised
+ * @rfn: The function to be called to process requests that have been
+ * placed on the queue.
+ *
+ * Description:
+ * If a block device wishes to use the standard request handling procedures,
+ * which sorts requests and coalesces adjacent requests, then it must
+ * call blk_init_queue(). The function @rfn will be called when there
+ * are requests on the queue that need to be processed. If the device
+ * supports plugging, then @rfn may not be called immediately when requests
+ * are available on the queue, but may be called at some time later instead.
+ * Plugged queues are generally unplugged when a buffer belonging to one
+ * of the requests on the queue is needed, or due to memory pressure.
+ *
+ * @rfn is not required, or even expected, to remove all requests off the
+ * queue, but only as many as it can handle at a time. If it does leave
+ * requests on the queue, it is responsible for arranging that the requests
+ * get dealt with eventually.
+ *
+ * A global spin lock $io_request_lock must be held while manipulating the
+ * requests on the request queue.
+ *
+ * The request on the head of the queue is by default assumed to be
+ * potentially active, and it is not considered for re-ordering or merging
+ * whenever the given queue is unplugged. This behaviour can be changed with
+ * blk_queue_headactive().
+ *
+ * Note:
+ * blk_init_queue() must be paired with a blk_cleanup_queue() call
+ * when the block device is deactivated (such as at module unload).
+ **/
+void blk_init_queue(request_queue_t * q, request_fn_proc * rfn)
+{
+ INIT_LIST_HEAD(&q->queue_head);
+ elevator_init(&q->elevator, ELEVATOR_LINUS);
+ blk_init_free_list(q);
+ q->request_fn = rfn;
+ q->back_merge_fn = ll_back_merge_fn;
+ q->front_merge_fn = ll_front_merge_fn;
+ q->merge_requests_fn = ll_merge_requests_fn;
+ q->make_request_fn = __make_request;
+ q->plug_tq.sync = 0;
+ q->plug_tq.routine = &generic_unplug_device;
+ q->plug_tq.data = q;
+ q->plugged = 0;
+ /*
+ * These booleans describe the queue properties. We set the
+ * default (and most common) values here. Other drivers can
+ * use the appropriate functions to alter the queue properties.
+ * as appropriate.
+ */
+ q->plug_device_fn = generic_plug_device;
+ q->head_active = 1;
+
+ blk_queue_bounce_limit(q, BLK_BOUNCE_HIGH);
+}
+
+#define blkdev_free_rq(list) list_entry((list)->next, struct request, queue);
+/*
+ * Get a free request. io_request_lock must be held and interrupts
+ * disabled on the way in. Returns NULL if there are no free requests.
+ */
+static struct request *get_request(request_queue_t *q, int rw)
+{
+ struct request *rq = NULL;
+ struct request_list *rl = q->rq + rw;
+
+ if (!list_empty(&rl->free)) {
+ rq = blkdev_free_rq(&rl->free);
+ list_del(&rq->queue);
+ rl->count--;
+ rq->rq_status = RQ_ACTIVE;
+ rq->cmd = rw;
+ rq->special = NULL;
+ rq->q = q;
+ }
+
+ return rq;
+}
+
+/*
+ * Here's the request allocation design:
+ *
+ * 1: Blocking on request exhaustion is a key part of I/O throttling.
+ *
+ * 2: We want to be `fair' to all requesters. We must avoid starvation, and
+ * attempt to ensure that all requesters sleep for a similar duration. Hence
+ * no stealing requests when there are other processes waiting.
+ *
+ * 3: We also wish to support `batching' of requests. So when a process is
+ * woken, we want to allow it to allocate a decent number of requests
+ * before it blocks again, so they can be nicely merged (this only really
+ * matters if the process happens to be adding requests near the head of
+ * the queue).
+ *
+ * 4: We want to avoid scheduling storms. This isn't really important, because
+ * the system will be I/O bound anyway. But it's easy.
+ *
+ * There is tension between requirements 2 and 3. Once a task has woken,
+ * we don't want to allow it to sleep as soon as it takes its second request.
+ * But we don't want currently-running tasks to steal all the requests
+ * from the sleepers. We handle this with wakeup hysteresis around
+ * 0 .. batch_requests and with the assumption that request taking is much,
+ * much faster than request freeing.
+ *
+ * So here's what we do:
+ *
+ * a) A READA requester fails if free_requests < batch_requests
+ *
+ * We don't want READA requests to prevent sleepers from ever
+ * waking. Note that READA is used extremely rarely - a few
+ * filesystems use it for directory readahead.
+ *
+ * When a process wants a new request:
+ *
+ * b) If free_requests == 0, the requester sleeps in FIFO manner.
+ *
+ * b) If 0 < free_requests < batch_requests and there are waiters,
+ * we still take a request non-blockingly. This provides batching.
+ *
+ * c) If free_requests >= batch_requests, the caller is immediately
+ * granted a new request.
+ *
+ * When a request is released:
+ *
+ * d) If free_requests < batch_requests, do nothing.
+ *
+ * f) If free_requests >= batch_requests, wake up a single waiter.
+ *
+ * The net effect is that when a process is woken at the batch_requests level,
+ * it will be able to take approximately (batch_requests) requests before
+ * blocking again (at the tail of the queue).
+ *
+ * This all assumes that the rate of taking requests is much, much higher
+ * than the rate of releasing them. Which is very true.
+ *
+ * -akpm, Feb 2002.
+ */
+
+static struct request *__get_request_wait(request_queue_t *q, int rw)
+{
+ register struct request *rq;
+ DECLARE_WAITQUEUE(wait, current);
+
+ add_wait_queue(&q->wait_for_requests[rw], &wait);
+ do {
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ generic_unplug_device(q);
+ if (q->rq[rw].count == 0)
+ schedule();
+ spin_lock_irq(&io_request_lock);
+ rq = get_request(q, rw);
+ spin_unlock_irq(&io_request_lock);
+ } while (rq == NULL);
+ remove_wait_queue(&q->wait_for_requests[rw], &wait);
+ current->state = TASK_RUNNING;
+ return rq;
+}
+
+/* RO fail safe mechanism */
+
+static long ro_bits[MAX_BLKDEV][8];
+
+int is_read_only(kdev_t dev)
+{
+ int minor,major;
+
+ major = MAJOR(dev);
+ minor = MINOR(dev);
+ if (major < 0 || major >= MAX_BLKDEV) return 0;
+ return ro_bits[major][minor >> 5] & (1 << (minor & 31));
+}
+
+void set_device_ro(kdev_t dev,int flag)
+{
+ int minor,major;
+
+ major = MAJOR(dev);
+ minor = MINOR(dev);
+ if (major < 0 || major >= MAX_BLKDEV) return;
+ if (flag) ro_bits[major][minor >> 5] |= 1 << (minor & 31);
+ else ro_bits[major][minor >> 5] &= ~(1 << (minor & 31));
+}
+
+inline void drive_stat_acct (kdev_t dev, int rw,
+ unsigned long nr_sectors, int new_io)
+{
+ unsigned int major = MAJOR(dev);
+ unsigned int index;
+
+ index = disk_index(dev);
+ if ((index >= DK_MAX_DISK) || (major >= DK_MAX_MAJOR))
+ return;
+
+ kstat.dk_drive[major][index] += new_io;
+ if (rw == READ) {
+ kstat.dk_drive_rio[major][index] += new_io;
+ kstat.dk_drive_rblk[major][index] += nr_sectors;
+ } else if (rw == WRITE) {
+ kstat.dk_drive_wio[major][index] += new_io;
+ kstat.dk_drive_wblk[major][index] += nr_sectors;
+ } else
+ printk(KERN_ERR "drive_stat_acct: cmd not R/W?\n");
+}
+
+#ifdef CONFIG_BLK_STATS
+/*
+ * Return up to two hd_structs on which to do IO accounting for a given
+ * request.
+ *
+ * On a partitioned device, we want to account both against the partition
+ * and against the whole disk.
+ */
+static void locate_hd_struct(struct request *req,
+ struct hd_struct **hd1,
+ struct hd_struct **hd2)
+{
+ struct gendisk *gd;
+
+ *hd1 = NULL;
+ *hd2 = NULL;
+
+ gd = get_gendisk(req->rq_dev);
+ if (gd && gd->part) {
+ /* Mask out the partition bits: account for the entire disk */
+ int devnr = MINOR(req->rq_dev) >> gd->minor_shift;
+ int whole_minor = devnr << gd->minor_shift;
+
+ *hd1 = &gd->part[whole_minor];
+ if (whole_minor != MINOR(req->rq_dev))
+ *hd2= &gd->part[MINOR(req->rq_dev)];
+ }
+}
+
+/*
+ * Round off the performance stats on an hd_struct.
+ *
+ * The average IO queue length and utilisation statistics are maintained
+ * by observing the current state of the queue length and the amount of
+ * time it has been in this state for.
+ * Normally, that accounting is done on IO completion, but that can result
+ * in more than a second's worth of IO being accounted for within any one
+ * second, leading to >100% utilisation. To deal with that, we do a
+ * round-off before returning the results when reading /proc/partitions,
+ * accounting immediately for all queue usage up to the current jiffies and
+ * restarting the counters again.
+ */
+void disk_round_stats(struct hd_struct *hd)
+{
+ unsigned long now = jiffies;
+
+ hd->aveq += (hd->ios_in_flight * (jiffies - hd->last_queue_change));
+ hd->last_queue_change = now;
+
+ if (hd->ios_in_flight)
+ hd->io_ticks += (now - hd->last_idle_time);
+ hd->last_idle_time = now;
+}
+
+static inline void down_ios(struct hd_struct *hd)
+{
+ disk_round_stats(hd);
+ --hd->ios_in_flight;
+}
+
+static inline void up_ios(struct hd_struct *hd)
+{
+ disk_round_stats(hd);
+ ++hd->ios_in_flight;
+}
+
+static void account_io_start(struct hd_struct *hd, struct request *req,
+ int merge, int sectors)
+{
+ switch (req->cmd) {
+ case READ:
+ if (merge)
+ hd->rd_merges++;
+ hd->rd_sectors += sectors;
+ break;
+ case WRITE:
+ if (merge)
+ hd->wr_merges++;
+ hd->wr_sectors += sectors;
+ break;
+ }
+ if (!merge)
+ up_ios(hd);
+}
+
+static void account_io_end(struct hd_struct *hd, struct request *req)
+{
+ unsigned long duration = jiffies - req->start_time;
+ switch (req->cmd) {
+ case READ:
+ hd->rd_ticks += duration;
+ hd->rd_ios++;
+ break;
+ case WRITE:
+ hd->wr_ticks += duration;
+ hd->wr_ios++;
+ break;
+ }
+ down_ios(hd);
+}
+
+void req_new_io(struct request *req, int merge, int sectors)
+{
+ struct hd_struct *hd1, *hd2;
+
+ locate_hd_struct(req, &hd1, &hd2);
+ if (hd1)
+ account_io_start(hd1, req, merge, sectors);
+ if (hd2)
+ account_io_start(hd2, req, merge, sectors);
+}
+
+void req_merged_io(struct request *req)
+{
+ struct hd_struct *hd1, *hd2;
+
+ locate_hd_struct(req, &hd1, &hd2);
+ if (hd1)
+ down_ios(hd1);
+ if (hd2)
+ down_ios(hd2);
+}
+
+void req_finished_io(struct request *req)
+{
+ struct hd_struct *hd1, *hd2;
+
+ locate_hd_struct(req, &hd1, &hd2);
+ if (hd1)
+ account_io_end(hd1, req);
+ if (hd2)
+ account_io_end(hd2, req);
+}
+EXPORT_SYMBOL(req_finished_io);
+#endif /* CONFIG_BLK_STATS */
+
+/*
+ * add-request adds a request to the linked list.
+ * io_request_lock is held and interrupts disabled, as we muck with the
+ * request queue list.
+ *
+ * By this point, req->cmd is always either READ/WRITE, never READA,
+ * which is important for drive_stat_acct() above.
+ */
+static inline void add_request(request_queue_t * q, struct request * req,
+ struct list_head *insert_here)
+{
+ drive_stat_acct(req->rq_dev, req->cmd, req->nr_sectors, 1);
+
+ if (!q->plugged && q->head_active && insert_here == &q->queue_head) {
+ spin_unlock_irq(&io_request_lock);
+ printk("list_empty(&q->queue_head) is %d\n",
+ list_empty(&q->queue_head));
+ BUG();
+ }
+
+ /*
+ * elevator indicated where it wants this request to be
+ * inserted at elevator_merge time
+ */
+ list_add(&req->queue, insert_here);
+}
+
+/*
+ * Must be called with io_request_lock held and interrupts disabled
+ */
+void blkdev_release_request(struct request *req)
+{
+ request_queue_t *q = req->q;
+ int rw = req->cmd;
+
+ req->rq_status = RQ_INACTIVE;
+ req->q = NULL;
+
+ /*
+ * Request may not have originated from ll_rw_blk. if not,
+ * assume it has free buffers and check waiters
+ */
+ if (q) {
+ list_add(&req->queue, &q->rq[rw].free);
+ if (++q->rq[rw].count >= q->batch_requests)
+ wake_up(&q->wait_for_requests[rw]);
+ }
+}
+
+/*
+ * Has to be called with the request spinlock acquired
+ */
+static void attempt_merge(request_queue_t * q,
+ struct request *req,
+ int max_sectors,
+ int max_segments)
+{
+ struct request *next;
+
+ next = blkdev_next_request(req);
+ if (req->sector + req->nr_sectors != next->sector)
+ return;
+ if (req->cmd != next->cmd
+ || req->rq_dev != next->rq_dev
+ || req->nr_sectors + next->nr_sectors > max_sectors
+ || next->waiting)
+ return;
+ /*
+ * If we are not allowed to merge these requests, then
+ * return. If we are allowed to merge, then the count
+ * will have been updated to the appropriate number,
+ * and we shouldn't do it here too.
+ */
+ if (!q->merge_requests_fn(q, req, next, max_segments))
+ return;
+
+ q->elevator.elevator_merge_req_fn(req, next);
+ req->bhtail->b_reqnext = next->bh;
+ req->bhtail = next->bhtail;
+ req->nr_sectors = req->hard_nr_sectors += next->hard_nr_sectors;
+ list_del(&next->queue);
+
+ /* One last thing: we have removed a request, so we now have one
+ less expected IO to complete for accounting purposes. */
+ req_merged_io(req);
+
+ blkdev_release_request(next);
+}
+
+static inline void attempt_back_merge(request_queue_t * q,
+ struct request *req,
+ int max_sectors,
+ int max_segments)
+{
+ if (&req->queue == q->queue_head.prev)
+ return;
+ attempt_merge(q, req, max_sectors, max_segments);
+}
+
+static inline void attempt_front_merge(request_queue_t * q,
+ struct list_head * head,
+ struct request *req,
+ int max_sectors,
+ int max_segments)
+{
+ struct list_head * prev;
+
+ prev = req->queue.prev;
+ if (head == prev)
+ return;
+ attempt_merge(q, blkdev_entry_to_request(prev), max_sectors, max_segments);
+}
+
+static int __make_request(request_queue_t * q, int rw,
+ struct buffer_head * bh)
+{
+ unsigned int sector, count;
+ int max_segments = MAX_SEGMENTS;
+ struct request * req, *freereq = NULL;
+ int rw_ahead, max_sectors, el_ret;
+ struct list_head *head, *insert_here;
+ int latency;
+ elevator_t *elevator = &q->elevator;
+
+ count = bh->b_size >> 9;
+ sector = bh->b_rsector;
+
+ rw_ahead = 0; /* normal case; gets changed below for READA */
+ switch (rw) {
+ case READA:
+#if 0 /* bread() misinterprets failed READA attempts as IO errors on SMP */
+ rw_ahead = 1;
+#endif
+ rw = READ; /* drop into READ */
+ case READ:
+ case WRITE:
+ latency = elevator_request_latency(elevator, rw);
+ break;
+ default:
+ BUG();
+ goto end_io;
+ }
+
+ /* We'd better have a real physical mapping!
+ Check this bit only if the buffer was dirty and just locked
+ down by us so at this point flushpage will block and
+ won't clear the mapped bit under us. */
+ if (!buffer_mapped(bh))
+ BUG();
+
+ /*
+ * Temporary solution - in 2.5 this will be done by the lowlevel
+ * driver. Create a bounce buffer if the buffer data points into
+ * high memory - keep the original buffer otherwise.
+ */
+ bh = blk_queue_bounce(q, rw, bh);
+
+/* look for a free request. */
+ /*
+ * Try to coalesce the new request with old requests
+ */
+ max_sectors = get_max_sectors(bh->b_rdev);
+
+again:
+ req = NULL;
+ head = &q->queue_head;
+ /*
+ * Now we acquire the request spinlock, we have to be mega careful
+ * not to schedule or do something nonatomic
+ */
+ spin_lock_irq(&io_request_lock);
+
+ insert_here = head->prev;
+ if (list_empty(head)) {
+ q->plug_device_fn(q, bh->b_rdev); /* is atomic */
+ goto get_rq;
+ } else if (q->head_active && !q->plugged)
+ head = head->next;
+
+ el_ret = elevator->elevator_merge_fn(q, &req, head, bh, rw,max_sectors);
+ switch (el_ret) {
+
+ case ELEVATOR_BACK_MERGE:
+ if (!q->back_merge_fn(q, req, bh, max_segments)) {
+ insert_here = &req->queue;
+ break;
+ }
+ req->bhtail->b_reqnext = bh;
+ req->bhtail = bh;
+ req->nr_sectors = req->hard_nr_sectors += count;
+ blk_started_io(count);
+ drive_stat_acct(req->rq_dev, req->cmd, count, 0);
+ req_new_io(req, 1, count);
+ attempt_back_merge(q, req, max_sectors, max_segments);
+ goto out;
+
+ case ELEVATOR_FRONT_MERGE:
+ if (!q->front_merge_fn(q, req, bh, max_segments)) {
+ insert_here = req->queue.prev;
+ break;
+ }
+ bh->b_reqnext = req->bh;
+ req->bh = bh;
+ /*
+ * may not be valid, but queues not having bounce
+ * enabled for highmem pages must not look at
+ * ->buffer anyway
+ */
+ req->buffer = bh->b_data;
+ req->current_nr_sectors = req->hard_cur_sectors = count;
+ req->sector = req->hard_sector = sector;
+ req->nr_sectors = req->hard_nr_sectors += count;
+ blk_started_io(count);
+ drive_stat_acct(req->rq_dev, req->cmd, count, 0);
+ req_new_io(req, 1, count);
+ attempt_front_merge(q, head, req, max_sectors, max_segments);
+ goto out;
+
+ /*
+ * elevator says don't/can't merge. get new request
+ */
+ case ELEVATOR_NO_MERGE:
+ /*
+ * use elevator hints as to where to insert the
+ * request. if no hints, just add it to the back
+ * of the queue
+ */
+ if (req)
+ insert_here = &req->queue;
+ break;
+
+ default:
+ printk("elevator returned crap (%d)\n", el_ret);
+ BUG();
+ }
+
+get_rq:
+ if (freereq) {
+ req = freereq;
+ freereq = NULL;
+ } else {
+ /*
+ * See description above __get_request_wait()
+ */
+ if (rw_ahead) {
+ if (q->rq[rw].count < q->batch_requests) {
+ spin_unlock_irq(&io_request_lock);
+ goto end_io;
+ }
+ req = get_request(q, rw);
+ if (req == NULL)
+ BUG();
+ } else {
+ req = get_request(q, rw);
+ if (req == NULL) {
+ spin_unlock_irq(&io_request_lock);
+ freereq = __get_request_wait(q, rw);
+ goto again;
+ }
+ }
+ }
+
+/* fill up the request-info, and add it to the queue */
+ req->elevator_sequence = latency;
+ req->cmd = rw;
+ req->errors = 0;
+ req->hard_sector = req->sector = sector;
+ req->hard_nr_sectors = req->nr_sectors = count;
+ req->current_nr_sectors = req->hard_cur_sectors = count;
+ req->nr_segments = 1; /* Always 1 for a new request. */
+ req->nr_hw_segments = 1; /* Always 1 for a new request. */
+ req->buffer = bh->b_data;
+ req->waiting = NULL;
+ req->bh = bh;
+ req->bhtail = bh;
+ req->rq_dev = bh->b_rdev;
+ req->start_time = jiffies;
+ req_new_io(req, 0, count);
+ blk_started_io(count);
+ add_request(q, req, insert_here);
+out:
+ if (freereq)
+ blkdev_release_request(freereq);
+ spin_unlock_irq(&io_request_lock);
+ return 0;
+end_io:
+ bh->b_end_io(bh, test_bit(BH_Uptodate, &bh->b_state));
+ return 0;
+}
+
+/**
+ * generic_make_request: hand a buffer head to it's device driver for I/O
+ * @rw: READ, WRITE, or READA - what sort of I/O is desired.
+ * @bh: The buffer head describing the location in memory and on the device.
+ *
+ * generic_make_request() is used to make I/O requests of block
+ * devices. It is passed a &struct buffer_head and a &rw value. The
+ * %READ and %WRITE options are (hopefully) obvious in meaning. The
+ * %READA value means that a read is required, but that the driver is
+ * free to fail the request if, for example, it cannot get needed
+ * resources immediately.
+ *
+ * generic_make_request() does not return any status. The
+ * success/failure status of the request, along with notification of
+ * completion, is delivered asynchronously through the bh->b_end_io
+ * function described (one day) else where.
+ *
+ * The caller of generic_make_request must make sure that b_page,
+ * b_addr, b_size are set to describe the memory buffer, that b_rdev
+ * and b_rsector are set to describe the device address, and the
+ * b_end_io and optionally b_private are set to describe how
+ * completion notification should be signaled. BH_Mapped should also
+ * be set (to confirm that b_dev and b_blocknr are valid).
+ *
+ * generic_make_request and the drivers it calls may use b_reqnext,
+ * and may change b_rdev and b_rsector. So the values of these fields
+ * should NOT be depended on after the call to generic_make_request.
+ * Because of this, the caller should record the device address
+ * information in b_dev and b_blocknr.
+ *
+ * Apart from those fields mentioned above, no other fields, and in
+ * particular, no other flags, are changed by generic_make_request or
+ * any lower level drivers.
+ * */
+void generic_make_request (int rw, struct buffer_head * bh)
+{
+ int major = MAJOR(bh->b_rdev);
+ int minorsize = 0;
+ request_queue_t *q;
+
+ if (!bh->b_end_io)
+ BUG();
+
+ /* Test device size, when known. */
+ if (blk_size[major])
+ minorsize = blk_size[major][MINOR(bh->b_rdev)];
+ if (minorsize) {
+ unsigned long maxsector = (minorsize << 1) + 1;
+ unsigned long sector = bh->b_rsector;
+ unsigned int count = bh->b_size >> 9;
+
+ if (maxsector < count || maxsector - count < sector) {
+ /* Yecch */
+ bh->b_state &= ~(1 << BH_Dirty);
+
+ /* This may well happen - the kernel calls bread()
+ without checking the size of the device, e.g.,
+ when mounting a device. */
+ printk(KERN_INFO
+ "attempt to access beyond end of device\n");
+ printk(KERN_INFO "%s: rw=%d, want=%ld, limit=%d\n",
+ kdevname(bh->b_rdev), rw,
+ (sector + count)>>1, minorsize);
+
+ bh->b_end_io(bh, 0);
+ return;
+ }
+ }
+
+ /*
+ * Resolve the mapping until finished. (drivers are
+ * still free to implement/resolve their own stacking
+ * by explicitly returning 0)
+ */
+ /* NOTE: we don't repeat the blk_size check for each new device.
+ * Stacking drivers are expected to know what they are doing.
+ */
+ do {
+ q = blk_get_queue(bh->b_rdev);
+ if (!q) {
+ printk(KERN_ERR
+ "generic_make_request: Trying to access "
+ "nonexistent block-device %s (%ld)\n",
+ kdevname(bh->b_rdev), bh->b_rsector);
+ buffer_IO_error(bh);
+ break;
+ }
+ } while (q->make_request_fn(q, rw, bh));
+}
+
+
+/**
+ * submit_bh: submit a buffer_head to the block device later for I/O
+ * @rw: whether to %READ or %WRITE, or maybe to %READA (read ahead)
+ * @bh: The &struct buffer_head which describes the I/O
+ *
+ * submit_bh() is very similar in purpose to generic_make_request(), and
+ * uses that function to do most of the work.
+ *
+ * The extra functionality provided by submit_bh is to determine
+ * b_rsector from b_blocknr and b_size, and to set b_rdev from b_dev.
+ * This is is appropriate for IO requests that come from the buffer
+ * cache and page cache which (currently) always use aligned blocks.
+ */
+void submit_bh(int rw, struct buffer_head * bh)
+{
+ int count = bh->b_size >> 9;
+
+ if (!test_bit(BH_Lock, &bh->b_state))
+ BUG();
+
+ set_bit(BH_Req, &bh->b_state);
+ set_bit(BH_Launder, &bh->b_state);
+
+ /*
+ * First step, 'identity mapping' - RAID or LVM might
+ * further remap this.
+ */
+ bh->b_rdev = bh->b_dev;
+ bh->b_rsector = bh->b_blocknr * count;
+
+ generic_make_request(rw, bh);
+
+ switch (rw) {
+ case WRITE:
+ kstat.pgpgout += count;
+ break;
+ default:
+ kstat.pgpgin += count;
+ break;
+ }
+}
+
+/**
+ * ll_rw_block: low-level access to block devices
+ * @rw: whether to %READ or %WRITE or maybe %READA (readahead)
+ * @nr: number of &struct buffer_heads in the array
+ * @bhs: array of pointers to &struct buffer_head
+ *
+ * ll_rw_block() takes an array of pointers to &struct buffer_heads,
+ * and requests an I/O operation on them, either a %READ or a %WRITE.
+ * The third %READA option is described in the documentation for
+ * generic_make_request() which ll_rw_block() calls.
+ *
+ * This function provides extra functionality that is not in
+ * generic_make_request() that is relevant to buffers in the buffer
+ * cache or page cache. In particular it drops any buffer that it
+ * cannot get a lock on (with the BH_Lock state bit), any buffer that
+ * appears to be clean when doing a write request, and any buffer that
+ * appears to be up-to-date when doing read request. Further it marks
+ * as clean buffers that are processed for writing (the buffer cache
+ * wont assume that they are actually clean until the buffer gets
+ * unlocked).
+ *
+ * ll_rw_block sets b_end_io to simple completion handler that marks
+ * the buffer up-to-date (if approriate), unlocks the buffer and wakes
+ * any waiters. As client that needs a more interesting completion
+ * routine should call submit_bh() (or generic_make_request())
+ * directly.
+ *
+ * Caveat:
+ * All of the buffers must be for the same device, and must also be
+ * of the current approved size for the device. */
+
+void ll_rw_block(int rw, int nr, struct buffer_head * bhs[])
+{
+ unsigned int major;
+ int correct_size;
+ int i;
+
+ if (!nr)
+ return;
+
+ major = MAJOR(bhs[0]->b_dev);
+
+ /* Determine correct block size for this device. */
+ correct_size = get_hardsect_size(bhs[0]->b_dev);
+
+ /* Verify requested block sizes. */
+ for (i = 0; i < nr; i++) {
+ struct buffer_head *bh = bhs[i];
+ if (bh->b_size % correct_size) {
+ printk(KERN_NOTICE "ll_rw_block: device %s: "
+ "only %d-char blocks implemented (%u)\n",
+ kdevname(bhs[0]->b_dev),
+ correct_size, bh->b_size);
+ goto sorry;
+ }
+ }
+
+ if ((rw & WRITE) && is_read_only(bhs[0]->b_dev)) {
+ printk(KERN_NOTICE "Can't write to read-only device %s\n",
+ kdevname(bhs[0]->b_dev));
+ goto sorry;
+ }
+
+ for (i = 0; i < nr; i++) {
+ struct buffer_head *bh = bhs[i];
+
+ /* Only one thread can actually submit the I/O. */
+ if (test_and_set_bit(BH_Lock, &bh->b_state))
+ continue;
+
+ /* We have the buffer lock */
+ atomic_inc(&bh->b_count);
+ bh->b_end_io = end_buffer_io_sync;
+
+ switch(rw) {
+ case WRITE:
+ if (!atomic_set_buffer_clean(bh))
+ /* Hmmph! Nothing to write */
+ goto end_io;
+ __mark_buffer_clean(bh);
+ break;
+
+ case READA:
+ case READ:
+ if (buffer_uptodate(bh))
+ /* Hmmph! Already have it */
+ goto end_io;
+ break;
+ default:
+ BUG();
+ end_io:
+ bh->b_end_io(bh, test_bit(BH_Uptodate, &bh->b_state));
+ continue;
+ }
+
+ submit_bh(rw, bh);
+ }
+ return;
+
+sorry:
+ /* Make sure we don't get infinite dirty retries.. */
+ for (i = 0; i < nr; i++)
+ mark_buffer_clean(bhs[i]);
+}
+
+#ifdef CONFIG_STRAM_SWAP
+extern int stram_device_init (void);
+#endif
+
+
+/**
+ * end_that_request_first - end I/O on one buffer.
+ * @req: the request being processed
+ * @uptodate: 0 for I/O error
+ * @name: the name printed for an I/O error
+ *
+ * Description:
+ * Ends I/O on the first buffer attached to @req, and sets it up
+ * for the next buffer_head (if any) in the cluster.
+ *
+ * Return:
+ * 0 - we are done with this request, call end_that_request_last()
+ * 1 - still buffers pending for this request
+ *
+ * Caveat:
+ * Drivers implementing their own end_request handling must call
+ * blk_finished_io() appropriately.
+ **/
+
+int end_that_request_first (struct request *req, int uptodate, char *name)
+{
+ struct buffer_head * bh;
+ int nsect;
+
+ req->errors = 0;
+ if (!uptodate)
+ printk("end_request: I/O error, dev %s (%s), sector %lu\n",
+ kdevname(req->rq_dev), name, req->sector);
+
+ if ((bh = req->bh) != NULL) {
+ nsect = bh->b_size >> 9;
+ blk_finished_io(nsect);
+ req->bh = bh->b_reqnext;
+ bh->b_reqnext = NULL;
+ bh->b_end_io(bh, uptodate);
+ if ((bh = req->bh) != NULL) {
+ req->hard_sector += nsect;
+ req->hard_nr_sectors -= nsect;
+ req->sector = req->hard_sector;
+ req->nr_sectors = req->hard_nr_sectors;
+
+ req->current_nr_sectors = bh->b_size >> 9;
+ req->hard_cur_sectors = req->current_nr_sectors;
+ if (req->nr_sectors < req->current_nr_sectors) {
+ req->nr_sectors = req->current_nr_sectors;
+ printk("end_request: buffer-list destroyed\n");
+ }
+ req->buffer = bh->b_data;
+ return 1;
+ }
+ }
+ return 0;
+}
+
+void end_that_request_last(struct request *req)
+{
+ struct completion *waiting = req->waiting;
+
+ req_finished_io(req);
+ blkdev_release_request(req);
+ if (waiting)
+ complete(waiting);
+}
+
+int __init blk_dev_init(void)
+{
+ struct blk_dev_struct *dev;
+
+ request_cachep = kmem_cache_create("blkdev_requests",
+ sizeof(struct request),
+ 0, SLAB_HWCACHE_ALIGN, NULL, NULL);
+
+ if (!request_cachep)
+ panic("Can't create request pool slab cache\n");
+
+ for (dev = blk_dev + MAX_BLKDEV; dev-- != blk_dev;)
+ dev->queue = NULL;
+
+ memset(ro_bits,0,sizeof(ro_bits));
+ memset(max_readahead, 0, sizeof(max_readahead));
+ memset(max_sectors, 0, sizeof(max_sectors));
+
+ blk_max_low_pfn = max_low_pfn - 1;
+ blk_max_pfn = max_pfn - 1;
+
+#ifdef CONFIG_AMIGA_Z2RAM
+ z2_init();
+#endif
+#ifdef CONFIG_STRAM_SWAP
+ stram_device_init();
+#endif
+#ifdef CONFIG_ISP16_CDI
+ isp16_init();
+#endif
+#ifdef CONFIG_BLK_DEV_PS2
+ ps2esdi_init();
+#endif
+#ifdef CONFIG_BLK_DEV_XD
+ xd_init();
+#endif
+#ifdef CONFIG_BLK_DEV_MFM
+ mfm_init();
+#endif
+#ifdef CONFIG_PARIDE
+ { extern void paride_init(void); paride_init(); };
+#endif
+#ifdef CONFIG_MAC_FLOPPY
+ swim3_init();
+#endif
+#ifdef CONFIG_BLK_DEV_SWIM_IOP
+ swimiop_init();
+#endif
+#ifdef CONFIG_AMIGA_FLOPPY
+ amiga_floppy_init();
+#endif
+#ifdef CONFIG_ATARI_FLOPPY
+ atari_floppy_init();
+#endif
+#ifdef CONFIG_BLK_DEV_FD
+ floppy_init();
+#else
+#if defined(__i386__) && !defined(CONFIG_XENO) /* Do we even need this? */
+ outb_p(0xc, 0x3f2);
+#endif
+#endif
+#ifdef CONFIG_CDU31A
+ cdu31a_init();
+#endif
+#ifdef CONFIG_ATARI_ACSI
+ acsi_init();
+#endif
+#ifdef CONFIG_MCD
+ mcd_init();
+#endif
+#ifdef CONFIG_MCDX
+ mcdx_init();
+#endif
+#ifdef CONFIG_SBPCD
+ sbpcd_init();
+#endif
+#ifdef CONFIG_AZTCD
+ aztcd_init();
+#endif
+#ifdef CONFIG_CDU535
+ sony535_init();
+#endif
+#ifdef CONFIG_GSCD
+ gscd_init();
+#endif
+#ifdef CONFIG_CM206
+ cm206_init();
+#endif
+#ifdef CONFIG_OPTCD
+ optcd_init();
+#endif
+#ifdef CONFIG_SJCD
+ sjcd_init();
+#endif
+#ifdef CONFIG_APBLOCK
+ ap_init();
+#endif
+#ifdef CONFIG_DDV
+ ddv_init();
+#endif
+#ifdef CONFIG_MDISK
+ mdisk_init();
+#endif
+#ifdef CONFIG_DASD
+ dasd_init();
+#endif
+#if defined(CONFIG_S390_TAPE) && defined(CONFIG_S390_TAPE_BLOCK)
+ tapeblock_init();
+#endif
+#ifdef CONFIG_BLK_DEV_XPRAM
+ xpram_init();
+#endif
+
+#ifdef CONFIG_SUN_JSFLASH
+ jsfd_init();
+#endif
+
+#ifdef CONFIG_XENOLINUX_BLOCK
+ xlblk_init();
+ xlseg_init();
+ xlseg_proc_init();
+#endif
+
+ return 0;
+};
+
+EXPORT_SYMBOL(io_request_lock);
+EXPORT_SYMBOL(end_that_request_first);
+EXPORT_SYMBOL(end_that_request_last);
+EXPORT_SYMBOL(blk_grow_request_list);
+EXPORT_SYMBOL(blk_init_queue);
+EXPORT_SYMBOL(blk_get_queue);
+EXPORT_SYMBOL(blk_cleanup_queue);
+EXPORT_SYMBOL(blk_queue_headactive);
+EXPORT_SYMBOL(blk_queue_make_request);
+EXPORT_SYMBOL(generic_make_request);
+EXPORT_SYMBOL(blkdev_release_request);
+EXPORT_SYMBOL(generic_unplug_device);
+EXPORT_SYMBOL(blk_queue_bounce_limit);
+EXPORT_SYMBOL(blk_max_low_pfn);
+EXPORT_SYMBOL(blk_max_pfn);
+EXPORT_SYMBOL(blk_seg_merge_ok);
+EXPORT_SYMBOL(blk_nohighio);
--- /dev/null
+/*
+ * linux/drivers/char/tty_io.c
+ *
+ * Copyright (C) 1991, 1992 Linus Torvalds
+ */
+
+/*
+ * 'tty_io.c' gives an orthogonal feeling to tty's, be they consoles
+ * or rs-channels. It also implements echoing, cooked mode etc.
+ *
+ * Kill-line thanks to John T Kohl, who also corrected VMIN = VTIME = 0.
+ *
+ * Modified by Theodore Ts'o, 9/14/92, to dynamically allocate the
+ * tty_struct and tty_queue structures. Previously there was an array
+ * of 256 tty_struct's which was statically allocated, and the
+ * tty_queue structures were allocated at boot time. Both are now
+ * dynamically allocated only when the tty is open.
+ *
+ * Also restructured routines so that there is more of a separation
+ * between the high-level tty routines (tty_io.c and tty_ioctl.c) and
+ * the low-level tty routines (serial.c, pty.c, console.c). This
+ * makes for cleaner and more compact code. -TYT, 9/17/92
+ *
+ * Modified by Fred N. van Kempen, 01/29/93, to add line disciplines
+ * which can be dynamically activated and de-activated by the line
+ * discipline handling modules (like SLIP).
+ *
+ * NOTE: pay no attention to the line discipline code (yet); its
+ * interface is still subject to change in this version...
+ * -- TYT, 1/31/92
+ *
+ * Added functionality to the OPOST tty handling. No delays, but all
+ * other bits should be there.
+ * -- Nick Holloway <alfie@dcs.warwick.ac.uk>, 27th May 1993.
+ *
+ * Rewrote canonical mode and added more termios flags.
+ * -- julian@uhunix.uhcc.hawaii.edu (J. Cowley), 13Jan94
+ *
+ * Reorganized FASYNC support so mouse code can share it.
+ * -- ctm@ardi.com, 9Sep95
+ *
+ * New TIOCLINUX variants added.
+ * -- mj@k332.feld.cvut.cz, 19-Nov-95
+ *
+ * Restrict vt switching via ioctl()
+ * -- grif@cs.ucr.edu, 5-Dec-95
+ *
+ * Move console and virtual terminal code to more appropriate files,
+ * implement CONFIG_VT and generalize console device interface.
+ * -- Marko Kohtala <Marko.Kohtala@hut.fi>, March 97
+ *
+ * Rewrote init_dev and release_dev to eliminate races.
+ * -- Bill Hawes <whawes@star.net>, June 97
+ *
+ * Added devfs support.
+ * -- C. Scott Ananian <cananian@alumni.princeton.edu>, 13-Jan-1998
+ *
+ * Added support for a Unix98-style ptmx device.
+ * -- C. Scott Ananian <cananian@alumni.princeton.edu>, 14-Jan-1998
+ *
+ * Reduced memory usage for older ARM systems
+ * -- Russell King <rmk@arm.linux.org.uk>
+ *
+ * Move do_SAK() into process context. Less stack use in devfs functions.
+ * alloc_tty_struct() always uses kmalloc() -- Andrew Morton <andrewm@uow.edu.eu> 17Mar01
+ */
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/major.h>
+#include <linux/errno.h>
+#include <linux/signal.h>
+#include <linux/fcntl.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/tty.h>
+#include <linux/tty_driver.h>
+#include <linux/tty_flip.h>
+#include <linux/devpts_fs.h>
+#include <linux/file.h>
+#include <linux/console.h>
+#include <linux/timer.h>
+#include <linux/ctype.h>
+#include <linux/kd.h>
+#include <linux/mm.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/poll.h>
+#include <linux/proc_fs.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/smp_lock.h>
+
+#include <asm/uaccess.h>
+#include <asm/system.h>
+#include <asm/bitops.h>
+
+#include <linux/kbd_kern.h>
+#include <linux/vt_kern.h>
+#include <linux/selection.h>
+#include <linux/devfs_fs_kernel.h>
+
+#include <linux/kmod.h>
+
+#ifdef CONFIG_XEN_CONSOLE
+extern void xen_console_init(void);
+#endif
+
+#ifdef CONFIG_VT
+extern void con_init_devfs (void);
+#endif
+
+extern void disable_early_printk(void);
+
+#define CONSOLE_DEV MKDEV(TTY_MAJOR,0)
+#define TTY_DEV MKDEV(TTYAUX_MAJOR,0)
+#define SYSCONS_DEV MKDEV(TTYAUX_MAJOR,1)
+#define PTMX_DEV MKDEV(TTYAUX_MAJOR,2)
+
+#undef TTY_DEBUG_HANGUP
+
+#define TTY_PARANOIA_CHECK 1
+#define CHECK_TTY_COUNT 1
+
+struct termios tty_std_termios; /* for the benefit of tty drivers */
+struct tty_driver *tty_drivers; /* linked list of tty drivers */
+struct tty_ldisc ldiscs[NR_LDISCS]; /* line disc dispatch table */
+
+#ifdef CONFIG_UNIX98_PTYS
+extern struct tty_driver ptm_driver[]; /* Unix98 pty masters; for /dev/ptmx */
+extern struct tty_driver pts_driver[]; /* Unix98 pty slaves; for /dev/ptmx */
+#endif
+
+static void initialize_tty_struct(struct tty_struct *tty);
+
+static ssize_t tty_read(struct file *, char *, size_t, loff_t *);
+static ssize_t tty_write(struct file *, const char *, size_t, loff_t *);
+static unsigned int tty_poll(struct file *, poll_table *);
+static int tty_open(struct inode *, struct file *);
+static int tty_release(struct inode *, struct file *);
+int tty_ioctl(struct inode * inode, struct file * file,
+ unsigned int cmd, unsigned long arg);
+static int tty_fasync(int fd, struct file * filp, int on);
+extern int vme_scc_init (void);
+extern long vme_scc_console_init(void);
+extern int serial167_init(void);
+extern long serial167_console_init(void);
+extern void console_8xx_init(void);
+extern int rs_8xx_init(void);
+extern void mac_scc_console_init(void);
+extern void hwc_console_init(void);
+extern void hwc_tty_init(void);
+extern void con3215_init(void);
+extern void tty3215_init(void);
+extern void tub3270_con_init(void);
+extern void tub3270_init(void);
+extern void rs285_console_init(void);
+extern void sa1100_rs_console_init(void);
+extern void sgi_serial_console_init(void);
+extern void sci_console_init(void);
+extern void tx3912_console_init(void);
+extern void tx3912_rs_init(void);
+extern void txx927_console_init(void);
+extern void sb1250_serial_console_init(void);
+
+#ifndef MIN
+#define MIN(a,b) ((a) < (b) ? (a) : (b))
+#endif
+#ifndef MAX
+#define MAX(a,b) ((a) < (b) ? (b) : (a))
+#endif
+
+static struct tty_struct *alloc_tty_struct(void)
+{
+ struct tty_struct *tty;
+
+ tty = kmalloc(sizeof(struct tty_struct), GFP_KERNEL);
+ if (tty)
+ memset(tty, 0, sizeof(struct tty_struct));
+ return tty;
+}
+
+static inline void free_tty_struct(struct tty_struct *tty)
+{
+ kfree(tty);
+}
+
+/*
+ * This routine returns the name of tty.
+ */
+static char *
+_tty_make_name(struct tty_struct *tty, const char *name, char *buf)
+{
+ int idx = (tty)?MINOR(tty->device) - tty->driver.minor_start:0;
+
+ if (!tty) /* Hmm. NULL pointer. That's fun. */
+ strcpy(buf, "NULL tty");
+ else
+ sprintf(buf, name,
+ idx + tty->driver.name_base);
+
+ return buf;
+}
+
+#define TTY_NUMBER(tty) (MINOR((tty)->device) - (tty)->driver.minor_start + \
+ (tty)->driver.name_base)
+
+char *tty_name(struct tty_struct *tty, char *buf)
+{
+ return _tty_make_name(tty, (tty)?tty->driver.name:NULL, buf);
+}
+
+inline int tty_paranoia_check(struct tty_struct *tty, kdev_t device,
+ const char *routine)
+{
+#ifdef TTY_PARANOIA_CHECK
+ static const char badmagic[] = KERN_WARNING
+ "Warning: bad magic number for tty struct (%s) in %s\n";
+ static const char badtty[] = KERN_WARNING
+ "Warning: null TTY for (%s) in %s\n";
+
+ if (!tty) {
+ printk(badtty, kdevname(device), routine);
+ return 1;
+ }
+ if (tty->magic != TTY_MAGIC) {
+ printk(badmagic, kdevname(device), routine);
+ return 1;
+ }
+#endif
+ return 0;
+}
+
+static int check_tty_count(struct tty_struct *tty, const char *routine)
+{
+#ifdef CHECK_TTY_COUNT
+ struct list_head *p;
+ int count = 0;
+
+ file_list_lock();
+ for(p = tty->tty_files.next; p != &tty->tty_files; p = p->next) {
+ if(list_entry(p, struct file, f_list)->private_data == tty)
+ count++;
+ }
+ file_list_unlock();
+ if (tty->driver.type == TTY_DRIVER_TYPE_PTY &&
+ tty->driver.subtype == PTY_TYPE_SLAVE &&
+ tty->link && tty->link->count)
+ count++;
+ if (tty->count != count) {
+ printk(KERN_WARNING "Warning: dev (%s) tty->count(%d) "
+ "!= #fd's(%d) in %s\n",
+ kdevname(tty->device), tty->count, count, routine);
+ return count;
+ }
+#endif
+ return 0;
+}
+
+int tty_register_ldisc(int disc, struct tty_ldisc *new_ldisc)
+{
+ if (disc < N_TTY || disc >= NR_LDISCS)
+ return -EINVAL;
+
+ if (new_ldisc) {
+ ldiscs[disc] = *new_ldisc;
+ ldiscs[disc].flags |= LDISC_FLAG_DEFINED;
+ ldiscs[disc].num = disc;
+ } else
+ memset(&ldiscs[disc], 0, sizeof(struct tty_ldisc));
+
+ return 0;
+}
+
+EXPORT_SYMBOL(tty_register_ldisc);
+
+/* Set the discipline of a tty line. */
+static int tty_set_ldisc(struct tty_struct *tty, int ldisc)
+{
+ int retval = 0;
+ struct tty_ldisc o_ldisc;
+ char buf[64];
+
+ if ((ldisc < N_TTY) || (ldisc >= NR_LDISCS))
+ return -EINVAL;
+ /* Eduardo Blanco <ejbs@cs.cs.com.uy> */
+ /* Cyrus Durgin <cider@speakeasy.org> */
+ if (!(ldiscs[ldisc].flags & LDISC_FLAG_DEFINED)) {
+ char modname [20];
+ sprintf(modname, "tty-ldisc-%d", ldisc);
+ request_module (modname);
+ }
+ if (!(ldiscs[ldisc].flags & LDISC_FLAG_DEFINED))
+ return -EINVAL;
+
+ if (tty->ldisc.num == ldisc)
+ return 0; /* We are already in the desired discipline */
+ o_ldisc = tty->ldisc;
+
+ tty_wait_until_sent(tty, 0);
+
+ /* Shutdown the current discipline. */
+ if (tty->ldisc.close)
+ (tty->ldisc.close)(tty);
+
+ /* Now set up the new line discipline. */
+ tty->ldisc = ldiscs[ldisc];
+ tty->termios->c_line = ldisc;
+ if (tty->ldisc.open)
+ retval = (tty->ldisc.open)(tty);
+ if (retval < 0) {
+ tty->ldisc = o_ldisc;
+ tty->termios->c_line = tty->ldisc.num;
+ if (tty->ldisc.open && (tty->ldisc.open(tty) < 0)) {
+ tty->ldisc = ldiscs[N_TTY];
+ tty->termios->c_line = N_TTY;
+ if (tty->ldisc.open) {
+ int r = tty->ldisc.open(tty);
+
+ if (r < 0)
+ panic("Couldn't open N_TTY ldisc for "
+ "%s --- error %d.",
+ tty_name(tty, buf), r);
+ }
+ }
+ }
+ if (tty->ldisc.num != o_ldisc.num && tty->driver.set_ldisc)
+ tty->driver.set_ldisc(tty);
+ return retval;
+}
+
+/*
+ * This routine returns a tty driver structure, given a device number
+ */
+struct tty_driver *get_tty_driver(kdev_t device)
+{
+ int major, minor;
+ struct tty_driver *p;
+
+ minor = MINOR(device);
+ major = MAJOR(device);
+
+ for (p = tty_drivers; p; p = p->next) {
+ if (p->major != major)
+ continue;
+ if (minor < p->minor_start)
+ continue;
+ if (minor >= p->minor_start + p->num)
+ continue;
+ return p;
+ }
+ return NULL;
+}
+
+/*
+ * If we try to write to, or set the state of, a terminal and we're
+ * not in the foreground, send a SIGTTOU. If the signal is blocked or
+ * ignored, go ahead and perform the operation. (POSIX 7.2)
+ */
+int tty_check_change(struct tty_struct * tty)
+{
+ if (current->tty != tty)
+ return 0;
+ if (tty->pgrp <= 0) {
+ printk(KERN_WARNING "tty_check_change: tty->pgrp <= 0!\n");
+ return 0;
+ }
+ if (current->pgrp == tty->pgrp)
+ return 0;
+ if (is_ignored(SIGTTOU))
+ return 0;
+ if (is_orphaned_pgrp(current->pgrp))
+ return -EIO;
+ (void) kill_pg(current->pgrp,SIGTTOU,1);
+ return -ERESTARTSYS;
+}
+
+static ssize_t hung_up_tty_read(struct file * file, char * buf,
+ size_t count, loff_t *ppos)
+{
+ /* Can't seek (pread) on ttys. */
+ if (ppos != &file->f_pos)
+ return -ESPIPE;
+ return 0;
+}
+
+static ssize_t hung_up_tty_write(struct file * file, const char * buf,
+ size_t count, loff_t *ppos)
+{
+ /* Can't seek (pwrite) on ttys. */
+ if (ppos != &file->f_pos)
+ return -ESPIPE;
+ return -EIO;
+}
+
+/* No kernel lock held - none needed ;) */
+static unsigned int hung_up_tty_poll(struct file * filp, poll_table * wait)
+{
+ return POLLIN | POLLOUT | POLLERR | POLLHUP | POLLRDNORM | POLLWRNORM;
+}
+
+static int hung_up_tty_ioctl(struct inode * inode, struct file * file,
+ unsigned int cmd, unsigned long arg)
+{
+ return cmd == TIOCSPGRP ? -ENOTTY : -EIO;
+}
+
+static struct file_operations tty_fops = {
+ llseek: no_llseek,
+ read: tty_read,
+ write: tty_write,
+ poll: tty_poll,
+ ioctl: tty_ioctl,
+ open: tty_open,
+ release: tty_release,
+ fasync: tty_fasync,
+};
+
+static struct file_operations hung_up_tty_fops = {
+ llseek: no_llseek,
+ read: hung_up_tty_read,
+ write: hung_up_tty_write,
+ poll: hung_up_tty_poll,
+ ioctl: hung_up_tty_ioctl,
+ release: tty_release,
+};
+
+static spinlock_t redirect_lock = SPIN_LOCK_UNLOCKED;
+static struct file *redirect;
+/*
+ * This can be called by the "eventd" kernel thread. That is process synchronous,
+ * but doesn't hold any locks, so we need to make sure we have the appropriate
+ * locks for what we're doing..
+ */
+void do_tty_hangup(void *data)
+{
+ struct tty_struct *tty = (struct tty_struct *) data;
+ struct file * cons_filp = NULL;
+ struct file *f = NULL;
+ struct task_struct *p;
+ struct list_head *l;
+ int closecount = 0, n;
+
+ if (!tty)
+ return;
+
+ /* inuse_filps is protected by the single kernel lock */
+ lock_kernel();
+
+ spin_lock(&redirect_lock);
+ if (redirect && redirect->private_data == tty) {
+ f = redirect;
+ redirect = NULL;
+ }
+ spin_unlock(&redirect_lock);
+ if (f)
+ fput(f);
+
+ check_tty_count(tty, "do_tty_hangup");
+ file_list_lock();
+ for (l = tty->tty_files.next; l != &tty->tty_files; l = l->next) {
+ struct file * filp = list_entry(l, struct file, f_list);
+ if (filp->f_dentry->d_inode->i_rdev == CONSOLE_DEV ||
+ filp->f_dentry->d_inode->i_rdev == SYSCONS_DEV) {
+ cons_filp = filp;
+ continue;
+ }
+ if (filp->f_op != &tty_fops)
+ continue;
+ closecount++;
+ tty_fasync(-1, filp, 0); /* can't block */
+ filp->f_op = &hung_up_tty_fops;
+ }
+ file_list_unlock();
+
+ /* FIXME! What are the locking issues here? This may me overdoing things.. */
+ {
+ unsigned long flags;
+
+ save_flags(flags); cli();
+ if (tty->ldisc.flush_buffer)
+ tty->ldisc.flush_buffer(tty);
+ if (tty->driver.flush_buffer)
+ tty->driver.flush_buffer(tty);
+ if ((test_bit(TTY_DO_WRITE_WAKEUP, &tty->flags)) &&
+ tty->ldisc.write_wakeup)
+ (tty->ldisc.write_wakeup)(tty);
+ restore_flags(flags);
+ }
+
+ wake_up_interruptible(&tty->write_wait);
+ wake_up_interruptible(&tty->read_wait);
+
+ /*
+ * Shutdown the current line discipline, and reset it to
+ * N_TTY.
+ */
+ if (tty->driver.flags & TTY_DRIVER_RESET_TERMIOS)
+ *tty->termios = tty->driver.init_termios;
+ if (tty->ldisc.num != ldiscs[N_TTY].num) {
+ if (tty->ldisc.close)
+ (tty->ldisc.close)(tty);
+ tty->ldisc = ldiscs[N_TTY];
+ tty->termios->c_line = N_TTY;
+ if (tty->ldisc.open) {
+ int i = (tty->ldisc.open)(tty);
+ if (i < 0)
+ printk(KERN_ERR "do_tty_hangup: N_TTY open: "
+ "error %d\n", -i);
+ }
+ }
+
+ read_lock(&tasklist_lock);
+ for_each_task(p) {
+ if ((tty->session > 0) && (p->session == tty->session) &&
+ p->leader) {
+ send_sig(SIGHUP,p,1);
+ send_sig(SIGCONT,p,1);
+ if (tty->pgrp > 0)
+ p->tty_old_pgrp = tty->pgrp;
+ }
+ if (p->tty == tty)
+ p->tty = NULL;
+ }
+ read_unlock(&tasklist_lock);
+
+ tty->flags = 0;
+ tty->session = 0;
+ tty->pgrp = -1;
+ tty->ctrl_status = 0;
+ /*
+ * If one of the devices matches a console pointer, we
+ * cannot just call hangup() because that will cause
+ * tty->count and state->count to go out of sync.
+ * So we just call close() the right number of times.
+ */
+ if (cons_filp) {
+ if (tty->driver.close)
+ for (n = 0; n < closecount; n++)
+ tty->driver.close(tty, cons_filp);
+ } else if (tty->driver.hangup)
+ (tty->driver.hangup)(tty);
+ unlock_kernel();
+}
+
+void tty_hangup(struct tty_struct * tty)
+{
+#ifdef TTY_DEBUG_HANGUP
+ char buf[64];
+
+ printk(KERN_DEBUG "%s hangup...\n", tty_name(tty, buf));
+#endif
+ schedule_task(&tty->tq_hangup);
+}
+
+void tty_vhangup(struct tty_struct * tty)
+{
+#ifdef TTY_DEBUG_HANGUP
+ char buf[64];
+
+ printk(KERN_DEBUG "%s vhangup...\n", tty_name(tty, buf));
+#endif
+ do_tty_hangup((void *) tty);
+}
+
+int tty_hung_up_p(struct file * filp)
+{
+ return (filp->f_op == &hung_up_tty_fops);
+}
+
+/*
+ * This function is typically called only by the session leader, when
+ * it wants to disassociate itself from its controlling tty.
+ *
+ * It performs the following functions:
+ * (1) Sends a SIGHUP and SIGCONT to the foreground process group
+ * (2) Clears the tty from being controlling the session
+ * (3) Clears the controlling tty for all processes in the
+ * session group.
+ *
+ * The argument on_exit is set to 1 if called when a process is
+ * exiting; it is 0 if called by the ioctl TIOCNOTTY.
+ */
+void disassociate_ctty(int on_exit)
+{
+ struct tty_struct *tty = current->tty;
+ struct task_struct *p;
+ int tty_pgrp = -1;
+
+ if (tty) {
+ tty_pgrp = tty->pgrp;
+ if (on_exit && tty->driver.type != TTY_DRIVER_TYPE_PTY)
+ tty_vhangup(tty);
+ } else {
+ if (current->tty_old_pgrp) {
+ kill_pg(current->tty_old_pgrp, SIGHUP, on_exit);
+ kill_pg(current->tty_old_pgrp, SIGCONT, on_exit);
+ }
+ return;
+ }
+ if (tty_pgrp > 0) {
+ kill_pg(tty_pgrp, SIGHUP, on_exit);
+ if (!on_exit)
+ kill_pg(tty_pgrp, SIGCONT, on_exit);
+ }
+
+ current->tty_old_pgrp = 0;
+ tty->session = 0;
+ tty->pgrp = -1;
+
+ read_lock(&tasklist_lock);
+ for_each_task(p)
+ if (p->session == current->session)
+ p->tty = NULL;
+ read_unlock(&tasklist_lock);
+}
+
+void stop_tty(struct tty_struct *tty)
+{
+ if (tty->stopped)
+ return;
+ tty->stopped = 1;
+ if (tty->link && tty->link->packet) {
+ tty->ctrl_status &= ~TIOCPKT_START;
+ tty->ctrl_status |= TIOCPKT_STOP;
+ wake_up_interruptible(&tty->link->read_wait);
+ }
+ if (tty->driver.stop)
+ (tty->driver.stop)(tty);
+}
+
+void start_tty(struct tty_struct *tty)
+{
+ if (!tty->stopped || tty->flow_stopped)
+ return;
+ tty->stopped = 0;
+ if (tty->link && tty->link->packet) {
+ tty->ctrl_status &= ~TIOCPKT_STOP;
+ tty->ctrl_status |= TIOCPKT_START;
+ wake_up_interruptible(&tty->link->read_wait);
+ }
+ if (tty->driver.start)
+ (tty->driver.start)(tty);
+ if ((test_bit(TTY_DO_WRITE_WAKEUP, &tty->flags)) &&
+ tty->ldisc.write_wakeup)
+ (tty->ldisc.write_wakeup)(tty);
+ wake_up_interruptible(&tty->write_wait);
+}
+
+static ssize_t tty_read(struct file * file, char * buf, size_t count,
+ loff_t *ppos)
+{
+ int i;
+ struct tty_struct * tty;
+ struct inode *inode;
+
+ /* Can't seek (pread) on ttys. */
+ if (ppos != &file->f_pos)
+ return -ESPIPE;
+
+ tty = (struct tty_struct *)file->private_data;
+ inode = file->f_dentry->d_inode;
+ if (tty_paranoia_check(tty, inode->i_rdev, "tty_read"))
+ return -EIO;
+ if (!tty || (test_bit(TTY_IO_ERROR, &tty->flags)))
+ return -EIO;
+
+ /* This check not only needs to be done before reading, but also
+ whenever read_chan() gets woken up after sleeping, so I've
+ moved it to there. This should only be done for the N_TTY
+ line discipline, anyway. Same goes for write_chan(). -- jlc. */
+#if 0
+ if ((inode->i_rdev != CONSOLE_DEV) && /* don't stop on /dev/console */
+ (tty->pgrp > 0) &&
+ (current->tty == tty) &&
+ (tty->pgrp != current->pgrp))
+ if (is_ignored(SIGTTIN) || is_orphaned_pgrp(current->pgrp))
+ return -EIO;
+ else {
+ (void) kill_pg(current->pgrp, SIGTTIN, 1);
+ return -ERESTARTSYS;
+ }
+#endif
+ lock_kernel();
+ if (tty->ldisc.read)
+ i = (tty->ldisc.read)(tty,file,buf,count);
+ else
+ i = -EIO;
+ unlock_kernel();
+ if (i > 0)
+ inode->i_atime = CURRENT_TIME;
+ return i;
+}
+
+/*
+ * Split writes up in sane blocksizes to avoid
+ * denial-of-service type attacks
+ */
+static inline ssize_t do_tty_write(
+ ssize_t (*write)(struct tty_struct *, struct file *, const unsigned char *, size_t),
+ struct tty_struct *tty,
+ struct file *file,
+ const unsigned char *buf,
+ size_t count)
+{
+ ssize_t ret = 0, written = 0;
+
+ if (file->f_flags & O_NONBLOCK) {
+ if (down_trylock(&tty->atomic_write))
+ return -EAGAIN;
+ }
+ else {
+ if (down_interruptible(&tty->atomic_write))
+ return -ERESTARTSYS;
+ }
+ if ( test_bit(TTY_NO_WRITE_SPLIT, &tty->flags) ) {
+ lock_kernel();
+ written = write(tty, file, buf, count);
+ unlock_kernel();
+ } else {
+ for (;;) {
+ unsigned long size = MAX(PAGE_SIZE*2,16384);
+ if (size > count)
+ size = count;
+ lock_kernel();
+ ret = write(tty, file, buf, size);
+ unlock_kernel();
+ if (ret <= 0)
+ break;
+ written += ret;
+ buf += ret;
+ count -= ret;
+ if (!count)
+ break;
+ ret = -ERESTARTSYS;
+ if (signal_pending(current))
+ break;
+ if (current->need_resched)
+ schedule();
+ }
+ }
+ if (written) {
+ file->f_dentry->d_inode->i_mtime = CURRENT_TIME;
+ ret = written;
+ }
+ up(&tty->atomic_write);
+ return ret;
+}
+
+
+static ssize_t tty_write(struct file * file, const char * buf, size_t count,
+ loff_t *ppos)
+{
+ int is_console;
+ struct tty_struct * tty;
+ struct inode *inode = file->f_dentry->d_inode;
+
+ /* Can't seek (pwrite) on ttys. */
+ if (ppos != &file->f_pos)
+ return -ESPIPE;
+
+ /*
+ * For now, we redirect writes from /dev/console as
+ * well as /dev/tty0.
+ */
+ inode = file->f_dentry->d_inode;
+ is_console = (inode->i_rdev == SYSCONS_DEV ||
+ inode->i_rdev == CONSOLE_DEV);
+
+ if (is_console) {
+ struct file *p = NULL;
+
+ spin_lock(&redirect_lock);
+ if (redirect) {
+ get_file(redirect);
+ p = redirect;
+ }
+ spin_unlock(&redirect_lock);
+
+ if (p) {
+ ssize_t res = p->f_op->write(p, buf, count, &p->f_pos);
+ fput(p);
+ return res;
+ }
+ }
+
+ tty = (struct tty_struct *)file->private_data;
+ if (tty_paranoia_check(tty, inode->i_rdev, "tty_write"))
+ return -EIO;
+ if (!tty || !tty->driver.write || (test_bit(TTY_IO_ERROR, &tty->flags)))
+ return -EIO;
+#if 0
+ if (!is_console && L_TOSTOP(tty) && (tty->pgrp > 0) &&
+ (current->tty == tty) && (tty->pgrp != current->pgrp)) {
+ if (is_orphaned_pgrp(current->pgrp))
+ return -EIO;
+ if (!is_ignored(SIGTTOU)) {
+ (void) kill_pg(current->pgrp, SIGTTOU, 1);
+ return -ERESTARTSYS;
+ }
+ }
+#endif
+ if (!tty->ldisc.write)
+ return -EIO;
+ return do_tty_write(tty->ldisc.write, tty, file,
+ (const unsigned char *)buf, count);
+}
+
+/* Semaphore to protect creating and releasing a tty */
+static DECLARE_MUTEX(tty_sem);
+
+static void down_tty_sem(int index)
+{
+ down(&tty_sem);
+}
+
+static void up_tty_sem(int index)
+{
+ up(&tty_sem);
+}
+
+static void release_mem(struct tty_struct *tty, int idx);
+
+/*
+ * WSH 06/09/97: Rewritten to remove races and properly clean up after a
+ * failed open. The new code protects the open with a semaphore, so it's
+ * really quite straightforward. The semaphore locking can probably be
+ * relaxed for the (most common) case of reopening a tty.
+ */
+static int init_dev(kdev_t device, struct tty_struct **ret_tty)
+{
+ struct tty_struct *tty, *o_tty;
+ struct termios *tp, **tp_loc, *o_tp, **o_tp_loc;
+ struct termios *ltp, **ltp_loc, *o_ltp, **o_ltp_loc;
+ struct tty_driver *driver;
+ int retval=0;
+ int idx;
+
+ driver = get_tty_driver(device);
+ if (!driver) {
+ return -ENODEV;
+ }
+
+ idx = MINOR(device) - driver->minor_start;
+
+ /*
+ * Check whether we need to acquire the tty semaphore to avoid
+ * race conditions. For now, play it safe.
+ */
+ down_tty_sem(idx);
+
+ /* check whether we're reopening an existing tty */
+ tty = driver->table[idx];
+ if (tty) goto fast_track;
+
+ /*
+ * First time open is complex, especially for PTY devices.
+ * This code guarantees that either everything succeeds and the
+ * TTY is ready for operation, or else the table slots are vacated
+ * and the allocated memory released. (Except that the termios
+ * and locked termios may be retained.)
+ */
+
+ o_tty = NULL;
+ tp = o_tp = NULL;
+ ltp = o_ltp = NULL;
+
+ tty = alloc_tty_struct();
+ if(!tty)
+ goto fail_no_mem;
+ initialize_tty_struct(tty);
+ tty->device = device;
+ tty->driver = *driver;
+
+ tp_loc = &driver->termios[idx];
+ if (!*tp_loc) {
+ tp = (struct termios *) kmalloc(sizeof(struct termios),
+ GFP_KERNEL);
+ if (!tp)
+ goto free_mem_out;
+ *tp = driver->init_termios;
+ }
+
+ ltp_loc = &driver->termios_locked[idx];
+ if (!*ltp_loc) {
+ ltp = (struct termios *) kmalloc(sizeof(struct termios),
+ GFP_KERNEL);
+ if (!ltp)
+ goto free_mem_out;
+ memset(ltp, 0, sizeof(struct termios));
+ }
+
+ if (driver->type == TTY_DRIVER_TYPE_PTY) {
+ o_tty = alloc_tty_struct();
+ if (!o_tty)
+ goto free_mem_out;
+ initialize_tty_struct(o_tty);
+ o_tty->device = (kdev_t) MKDEV(driver->other->major,
+ driver->other->minor_start + idx);
+ o_tty->driver = *driver->other;
+
+ o_tp_loc = &driver->other->termios[idx];
+ if (!*o_tp_loc) {
+ o_tp = (struct termios *)
+ kmalloc(sizeof(struct termios), GFP_KERNEL);
+ if (!o_tp)
+ goto free_mem_out;
+ *o_tp = driver->other->init_termios;
+ }
+
+ o_ltp_loc = &driver->other->termios_locked[idx];
+ if (!*o_ltp_loc) {
+ o_ltp = (struct termios *)
+ kmalloc(sizeof(struct termios), GFP_KERNEL);
+ if (!o_ltp)
+ goto free_mem_out;
+ memset(o_ltp, 0, sizeof(struct termios));
+ }
+
+ /*
+ * Everything allocated ... set up the o_tty structure.
+ */
+ driver->other->table[idx] = o_tty;
+ if (!*o_tp_loc)
+ *o_tp_loc = o_tp;
+ if (!*o_ltp_loc)
+ *o_ltp_loc = o_ltp;
+ o_tty->termios = *o_tp_loc;
+ o_tty->termios_locked = *o_ltp_loc;
+ (*driver->other->refcount)++;
+ if (driver->subtype == PTY_TYPE_MASTER)
+ o_tty->count++;
+
+ /* Establish the links in both directions */
+ tty->link = o_tty;
+ o_tty->link = tty;
+ }
+
+ /*
+ * All structures have been allocated, so now we install them.
+ * Failures after this point use release_mem to clean up, so
+ * there's no need to null out the local pointers.
+ */
+ driver->table[idx] = tty;
+
+ if (!*tp_loc)
+ *tp_loc = tp;
+ if (!*ltp_loc)
+ *ltp_loc = ltp;
+ tty->termios = *tp_loc;
+ tty->termios_locked = *ltp_loc;
+ (*driver->refcount)++;
+ tty->count++;
+
+ /*
+ * Structures all installed ... call the ldisc open routines.
+ * If we fail here just call release_mem to clean up. No need
+ * to decrement the use counts, as release_mem doesn't care.
+ */
+ if (tty->ldisc.open) {
+ retval = (tty->ldisc.open)(tty);
+ if (retval)
+ goto release_mem_out;
+ }
+ if (o_tty && o_tty->ldisc.open) {
+ retval = (o_tty->ldisc.open)(o_tty);
+ if (retval) {
+ if (tty->ldisc.close)
+ (tty->ldisc.close)(tty);
+ goto release_mem_out;
+ }
+ }
+ goto success;
+
+ /*
+ * This fast open can be used if the tty is already open.
+ * No memory is allocated, and the only failures are from
+ * attempting to open a closing tty or attempting multiple
+ * opens on a pty master.
+ */
+fast_track:
+ if (test_bit(TTY_CLOSING, &tty->flags)) {
+ retval = -EIO;
+ goto end_init;
+ }
+ if (driver->type == TTY_DRIVER_TYPE_PTY &&
+ driver->subtype == PTY_TYPE_MASTER) {
+ /*
+ * special case for PTY masters: only one open permitted,
+ * and the slave side open count is incremented as well.
+ */
+ if (tty->count) {
+ retval = -EIO;
+ goto end_init;
+ }
+ tty->link->count++;
+ }
+ tty->count++;
+ tty->driver = *driver; /* N.B. why do this every time?? */
+
+success:
+ *ret_tty = tty;
+
+ /* All paths come through here to release the semaphore */
+end_init:
+ up_tty_sem(idx);
+ return retval;
+
+ /* Release locally allocated memory ... nothing placed in slots */
+free_mem_out:
+ if (o_tp)
+ kfree(o_tp);
+ if (o_tty)
+ free_tty_struct(o_tty);
+ if (ltp)
+ kfree(ltp);
+ if (tp)
+ kfree(tp);
+ free_tty_struct(tty);
+
+fail_no_mem:
+ retval = -ENOMEM;
+ goto end_init;
+
+ /* call the tty release_mem routine to clean out this slot */
+release_mem_out:
+ printk(KERN_INFO "init_dev: ldisc open failed, "
+ "clearing slot %d\n", idx);
+ release_mem(tty, idx);
+ goto end_init;
+}
+
+/*
+ * Releases memory associated with a tty structure, and clears out the
+ * driver table slots.
+ */
+static void release_mem(struct tty_struct *tty, int idx)
+{
+ struct tty_struct *o_tty;
+ struct termios *tp;
+
+ if ((o_tty = tty->link) != NULL) {
+ o_tty->driver.table[idx] = NULL;
+ if (o_tty->driver.flags & TTY_DRIVER_RESET_TERMIOS) {
+ tp = o_tty->driver.termios[idx];
+ o_tty->driver.termios[idx] = NULL;
+ kfree(tp);
+ }
+ o_tty->magic = 0;
+ (*o_tty->driver.refcount)--;
+ list_del(&o_tty->tty_files);
+ free_tty_struct(o_tty);
+ }
+
+ tty->driver.table[idx] = NULL;
+ if (tty->driver.flags & TTY_DRIVER_RESET_TERMIOS) {
+ tp = tty->driver.termios[idx];
+ tty->driver.termios[idx] = NULL;
+ kfree(tp);
+ }
+ tty->magic = 0;
+ (*tty->driver.refcount)--;
+ list_del(&tty->tty_files);
+ free_tty_struct(tty);
+}
+
+/*
+ * Even releasing the tty structures is a tricky business.. We have
+ * to be very careful that the structures are all released at the
+ * same time, as interrupts might otherwise get the wrong pointers.
+ *
+ * WSH 09/09/97: rewritten to avoid some nasty race conditions that could
+ * lead to double frees or releasing memory still in use.
+ */
+static void release_dev(struct file * filp)
+{
+ struct tty_struct *tty, *o_tty;
+ int pty_master, tty_closing, o_tty_closing, do_sleep;
+ int idx;
+ char buf[64];
+
+ tty = (struct tty_struct *)filp->private_data;
+ if (tty_paranoia_check(tty, filp->f_dentry->d_inode->i_rdev, "release_dev"))
+ return;
+
+ check_tty_count(tty, "release_dev");
+
+ tty_fasync(-1, filp, 0);
+
+ idx = MINOR(tty->device) - tty->driver.minor_start;
+ pty_master = (tty->driver.type == TTY_DRIVER_TYPE_PTY &&
+ tty->driver.subtype == PTY_TYPE_MASTER);
+ o_tty = tty->link;
+
+#ifdef TTY_PARANOIA_CHECK
+ if (idx < 0 || idx >= tty->driver.num) {
+ printk(KERN_DEBUG "release_dev: bad idx when trying to "
+ "free (%s)\n", kdevname(tty->device));
+ return;
+ }
+ if (tty != tty->driver.table[idx]) {
+ printk(KERN_DEBUG "release_dev: driver.table[%d] not tty "
+ "for (%s)\n", idx, kdevname(tty->device));
+ return;
+ }
+ if (tty->termios != tty->driver.termios[idx]) {
+ printk(KERN_DEBUG "release_dev: driver.termios[%d] not termios "
+ "for (%s)\n",
+ idx, kdevname(tty->device));
+ return;
+ }
+ if (tty->termios_locked != tty->driver.termios_locked[idx]) {
+ printk(KERN_DEBUG "release_dev: driver.termios_locked[%d] not "
+ "termios_locked for (%s)\n",
+ idx, kdevname(tty->device));
+ return;
+ }
+#endif
+
+#ifdef TTY_DEBUG_HANGUP
+ printk(KERN_DEBUG "release_dev of %s (tty count=%d)...",
+ tty_name(tty, buf), tty->count);
+#endif
+
+#ifdef TTY_PARANOIA_CHECK
+ if (tty->driver.other) {
+ if (o_tty != tty->driver.other->table[idx]) {
+ printk(KERN_DEBUG "release_dev: other->table[%d] "
+ "not o_tty for (%s)\n",
+ idx, kdevname(tty->device));
+ return;
+ }
+ if (o_tty->termios != tty->driver.other->termios[idx]) {
+ printk(KERN_DEBUG "release_dev: other->termios[%d] "
+ "not o_termios for (%s)\n",
+ idx, kdevname(tty->device));
+ return;
+ }
+ if (o_tty->termios_locked !=
+ tty->driver.other->termios_locked[idx]) {
+ printk(KERN_DEBUG "release_dev: other->termios_locked["
+ "%d] not o_termios_locked for (%s)\n",
+ idx, kdevname(tty->device));
+ return;
+ }
+ if (o_tty->link != tty) {
+ printk(KERN_DEBUG "release_dev: bad pty pointers\n");
+ return;
+ }
+ }
+#endif
+
+ if (tty->driver.close)
+ tty->driver.close(tty, filp);
+
+ /*
+ * Sanity check: if tty->count is going to zero, there shouldn't be
+ * any waiters on tty->read_wait or tty->write_wait. We test the
+ * wait queues and kick everyone out _before_ actually starting to
+ * close. This ensures that we won't block while releasing the tty
+ * structure.
+ *
+ * The test for the o_tty closing is necessary, since the master and
+ * slave sides may close in any order. If the slave side closes out
+ * first, its count will be one, since the master side holds an open.
+ * Thus this test wouldn't be triggered at the time the slave closes,
+ * so we do it now.
+ *
+ * Note that it's possible for the tty to be opened again while we're
+ * flushing out waiters. By recalculating the closing flags before
+ * each iteration we avoid any problems.
+ */
+ while (1) {
+ tty_closing = tty->count <= 1;
+ o_tty_closing = o_tty &&
+ (o_tty->count <= (pty_master ? 1 : 0));
+ do_sleep = 0;
+
+ if (tty_closing) {
+ if (waitqueue_active(&tty->read_wait)) {
+ wake_up(&tty->read_wait);
+ do_sleep++;
+ }
+ if (waitqueue_active(&tty->write_wait)) {
+ wake_up(&tty->write_wait);
+ do_sleep++;
+ }
+ }
+ if (o_tty_closing) {
+ if (waitqueue_active(&o_tty->read_wait)) {
+ wake_up(&o_tty->read_wait);
+ do_sleep++;
+ }
+ if (waitqueue_active(&o_tty->write_wait)) {
+ wake_up(&o_tty->write_wait);
+ do_sleep++;
+ }
+ }
+ if (!do_sleep)
+ break;
+
+ printk(KERN_WARNING "release_dev: %s: read/write wait queue "
+ "active!\n", tty_name(tty, buf));
+ schedule();
+ }
+
+ /*
+ * The closing flags are now consistent with the open counts on
+ * both sides, and we've completed the last operation that could
+ * block, so it's safe to proceed with closing.
+ */
+ if (pty_master) {
+ if (--o_tty->count < 0) {
+ printk(KERN_WARNING "release_dev: bad pty slave count "
+ "(%d) for %s\n",
+ o_tty->count, tty_name(o_tty, buf));
+ o_tty->count = 0;
+ }
+ }
+ if (--tty->count < 0) {
+ printk(KERN_WARNING "release_dev: bad tty->count (%d) for %s\n",
+ tty->count, tty_name(tty, buf));
+ tty->count = 0;
+ }
+
+ /*
+ * We've decremented tty->count, so we should zero out
+ * filp->private_data, to break the link between the tty and
+ * the file descriptor. Otherwise if filp_close() blocks before
+ * the file descriptor is removed from the inuse_filp
+ * list, check_tty_count() could observe a discrepancy and
+ * printk a warning message to the user.
+ */
+ filp->private_data = 0;
+
+ /*
+ * Perform some housekeeping before deciding whether to return.
+ *
+ * Set the TTY_CLOSING flag if this was the last open. In the
+ * case of a pty we may have to wait around for the other side
+ * to close, and TTY_CLOSING makes sure we can't be reopened.
+ */
+ if(tty_closing)
+ set_bit(TTY_CLOSING, &tty->flags);
+ if(o_tty_closing)
+ set_bit(TTY_CLOSING, &o_tty->flags);
+
+ /*
+ * If _either_ side is closing, make sure there aren't any
+ * processes that still think tty or o_tty is their controlling
+ * tty.
+ */
+ if (tty_closing || o_tty_closing) {
+ struct task_struct *p;
+
+ read_lock(&tasklist_lock);
+ for_each_task(p) {
+ if (p->tty == tty || (o_tty && p->tty == o_tty))
+ p->tty = NULL;
+ }
+ read_unlock(&tasklist_lock);
+ }
+
+ /* check whether both sides are closing ... */
+ if (!tty_closing || (o_tty && !o_tty_closing))
+ return;
+
+#ifdef TTY_DEBUG_HANGUP
+ printk(KERN_DEBUG "freeing tty structure...");
+#endif
+
+ /*
+ * Shutdown the current line discipline, and reset it to N_TTY.
+ * N.B. why reset ldisc when we're releasing the memory??
+ */
+ if (tty->ldisc.close)
+ (tty->ldisc.close)(tty);
+ tty->ldisc = ldiscs[N_TTY];
+ tty->termios->c_line = N_TTY;
+ if (o_tty) {
+ if (o_tty->ldisc.close)
+ (o_tty->ldisc.close)(o_tty);
+ o_tty->ldisc = ldiscs[N_TTY];
+ }
+
+ /*
+ * Make sure that the tty's task queue isn't activated.
+ */
+ run_task_queue(&tq_timer);
+ flush_scheduled_tasks();
+
+ /*
+ * The release_mem function takes care of the details of clearing
+ * the slots and preserving the termios structure.
+ */
+ release_mem(tty, idx);
+}
+
+/*
+ * tty_open and tty_release keep up the tty count that contains the
+ * number of opens done on a tty. We cannot use the inode-count, as
+ * different inodes might point to the same tty.
+ *
+ * Open-counting is needed for pty masters, as well as for keeping
+ * track of serial lines: DTR is dropped when the last close happens.
+ * (This is not done solely through tty->count, now. - Ted 1/27/92)
+ *
+ * The termios state of a pty is reset on first open so that
+ * settings don't persist across reuse.
+ */
+static int tty_open(struct inode * inode, struct file * filp)
+{
+ struct tty_struct *tty;
+ int noctty, retval;
+ kdev_t device;
+ unsigned short saved_flags;
+ char buf[64];
+
+ saved_flags = filp->f_flags;
+retry_open:
+ noctty = filp->f_flags & O_NOCTTY;
+ device = inode->i_rdev;
+ if (device == TTY_DEV) {
+ if (!current->tty)
+ return -ENXIO;
+ device = current->tty->device;
+ filp->f_flags |= O_NONBLOCK; /* Don't let /dev/tty block */
+ /* noctty = 1; */
+ }
+#ifdef CONFIG_VT
+ if (device == CONSOLE_DEV) {
+ extern int fg_console;
+ device = MKDEV(TTY_MAJOR, fg_console + 1);
+ noctty = 1;
+ }
+#endif
+ if (device == SYSCONS_DEV) {
+ struct console *c = console_drivers;
+ while(c && !c->device)
+ c = c->next;
+ if (!c)
+ return -ENODEV;
+ device = c->device(c);
+ filp->f_flags |= O_NONBLOCK; /* Don't let /dev/console block */
+ noctty = 1;
+ }
+
+ if (device == PTMX_DEV) {
+#ifdef CONFIG_UNIX98_PTYS
+
+ /* find a free pty. */
+ int major, minor;
+ struct tty_driver *driver;
+
+ /* find a device that is not in use. */
+ retval = -1;
+ for ( major = 0 ; major < UNIX98_NR_MAJORS ; major++ ) {
+ driver = &ptm_driver[major];
+ for (minor = driver->minor_start ;
+ minor < driver->minor_start + driver->num ;
+ minor++) {
+ device = MKDEV(driver->major, minor);
+ if (!init_dev(device, &tty)) goto ptmx_found; /* ok! */
+ }
+ }
+ return -EIO; /* no free ptys */
+ ptmx_found:
+ set_bit(TTY_PTY_LOCK, &tty->flags); /* LOCK THE SLAVE */
+ minor -= driver->minor_start;
+ devpts_pty_new(driver->other->name_base + minor, MKDEV(driver->other->major, minor + driver->other->minor_start));
+ tty_register_devfs(&pts_driver[major], DEVFS_FL_DEFAULT,
+ pts_driver[major].minor_start + minor);
+ noctty = 1;
+ goto init_dev_done;
+
+#else /* CONFIG_UNIX_98_PTYS */
+
+ return -ENODEV;
+
+#endif /* CONFIG_UNIX_98_PTYS */
+ }
+
+ retval = init_dev(device, &tty);
+ if (retval)
+ return retval;
+
+#ifdef CONFIG_UNIX98_PTYS
+init_dev_done:
+#endif
+ filp->private_data = tty;
+ file_move(filp, &tty->tty_files);
+ check_tty_count(tty, "tty_open");
+ if (tty->driver.type == TTY_DRIVER_TYPE_PTY &&
+ tty->driver.subtype == PTY_TYPE_MASTER)
+ noctty = 1;
+#ifdef TTY_DEBUG_HANGUP
+ printk(KERN_DEBUG "opening %s...", tty_name(tty, buf));
+#endif
+ if (tty->driver.open)
+ retval = tty->driver.open(tty, filp);
+ else
+ retval = -ENODEV;
+ filp->f_flags = saved_flags;
+
+ if (!retval && test_bit(TTY_EXCLUSIVE, &tty->flags) && !suser())
+ retval = -EBUSY;
+
+ if (retval) {
+#ifdef TTY_DEBUG_HANGUP
+ printk(KERN_DEBUG "error %d in opening %s...", retval,
+ tty_name(tty, buf));
+#endif
+
+ release_dev(filp);
+ if (retval != -ERESTARTSYS)
+ return retval;
+ if (signal_pending(current))
+ return retval;
+ schedule();
+ /*
+ * Need to reset f_op in case a hangup happened.
+ */
+ filp->f_op = &tty_fops;
+ goto retry_open;
+ }
+ if (!noctty &&
+ current->leader &&
+ !current->tty &&
+ tty->session == 0) {
+ task_lock(current);
+ current->tty = tty;
+ task_unlock(current);
+ current->tty_old_pgrp = 0;
+ tty->session = current->session;
+ tty->pgrp = current->pgrp;
+ }
+ if ((tty->driver.type == TTY_DRIVER_TYPE_SERIAL) &&
+ (tty->driver.subtype == SERIAL_TYPE_CALLOUT) &&
+ (tty->count == 1)) {
+ static int nr_warns;
+ if (nr_warns < 5) {
+ printk(KERN_WARNING "tty_io.c: "
+ "process %d (%s) used obsolete /dev/%s - "
+ "update software to use /dev/ttyS%d\n",
+ current->pid, current->comm,
+ tty_name(tty, buf), TTY_NUMBER(tty));
+ nr_warns++;
+ }
+ }
+ return 0;
+}
+
+static int tty_release(struct inode * inode, struct file * filp)
+{
+ lock_kernel();
+ release_dev(filp);
+ unlock_kernel();
+ return 0;
+}
+
+/* No kernel lock held - fine */
+static unsigned int tty_poll(struct file * filp, poll_table * wait)
+{
+ struct tty_struct * tty;
+
+ tty = (struct tty_struct *)filp->private_data;
+ if (tty_paranoia_check(tty, filp->f_dentry->d_inode->i_rdev, "tty_poll"))
+ return 0;
+
+ if (tty->ldisc.poll)
+ return (tty->ldisc.poll)(tty, filp, wait);
+ return 0;
+}
+
+static int tty_fasync(int fd, struct file * filp, int on)
+{
+ struct tty_struct * tty;
+ int retval;
+
+ tty = (struct tty_struct *)filp->private_data;
+ if (tty_paranoia_check(tty, filp->f_dentry->d_inode->i_rdev, "tty_fasync"))
+ return 0;
+
+ retval = fasync_helper(fd, filp, on, &tty->fasync);
+ if (retval <= 0)
+ return retval;
+
+ if (on) {
+ if (!waitqueue_active(&tty->read_wait))
+ tty->minimum_to_wake = 1;
+ if (filp->f_owner.pid == 0) {
+ filp->f_owner.pid = (-tty->pgrp) ? : current->pid;
+ filp->f_owner.uid = current->uid;
+ filp->f_owner.euid = current->euid;
+ }
+ } else {
+ if (!tty->fasync && !waitqueue_active(&tty->read_wait))
+ tty->minimum_to_wake = N_TTY_BUF_SIZE;
+ }
+ return 0;
+}
+
+static int tiocsti(struct tty_struct *tty, char * arg)
+{
+ char ch, mbz = 0;
+
+ if ((current->tty != tty) && !suser())
+ return -EPERM;
+ if (get_user(ch, arg))
+ return -EFAULT;
+ tty->ldisc.receive_buf(tty, &ch, &mbz, 1);
+ return 0;
+}
+
+static int tiocgwinsz(struct tty_struct *tty, struct winsize * arg)
+{
+ if (copy_to_user(arg, &tty->winsize, sizeof(*arg)))
+ return -EFAULT;
+ return 0;
+}
+
+static int tiocswinsz(struct tty_struct *tty, struct tty_struct *real_tty,
+ struct winsize * arg)
+{
+ struct winsize tmp_ws;
+
+ if (copy_from_user(&tmp_ws, arg, sizeof(*arg)))
+ return -EFAULT;
+ if (!memcmp(&tmp_ws, &tty->winsize, sizeof(*arg)))
+ return 0;
+ if (tty->pgrp > 0)
+ kill_pg(tty->pgrp, SIGWINCH, 1);
+ if ((real_tty->pgrp != tty->pgrp) && (real_tty->pgrp > 0))
+ kill_pg(real_tty->pgrp, SIGWINCH, 1);
+ tty->winsize = tmp_ws;
+ real_tty->winsize = tmp_ws;
+ return 0;
+}
+
+static int tioccons(struct inode *inode, struct file *file)
+{
+ if (inode->i_rdev == SYSCONS_DEV ||
+ inode->i_rdev == CONSOLE_DEV) {
+ struct file *f;
+ if (!suser())
+ return -EPERM;
+ spin_lock(&redirect_lock);
+ f = redirect;
+ redirect = NULL;
+ spin_unlock(&redirect_lock);
+ if (f)
+ fput(f);
+ return 0;
+ }
+ spin_lock(&redirect_lock);
+ if (redirect) {
+ spin_unlock(&redirect_lock);
+ return -EBUSY;
+ }
+ get_file(file);
+ redirect = file;
+ spin_unlock(&redirect_lock);
+ return 0;
+}
+
+
+static int fionbio(struct file *file, int *arg)
+{
+ int nonblock;
+
+ if (get_user(nonblock, arg))
+ return -EFAULT;
+
+ if (nonblock)
+ file->f_flags |= O_NONBLOCK;
+ else
+ file->f_flags &= ~O_NONBLOCK;
+ return 0;
+}
+
+static int tiocsctty(struct tty_struct *tty, int arg)
+{
+ if (current->leader &&
+ (current->session == tty->session))
+ return 0;
+ /*
+ * The process must be a session leader and
+ * not have a controlling tty already.
+ */
+ if (!current->leader || current->tty)
+ return -EPERM;
+ if (tty->session > 0) {
+ /*
+ * This tty is already the controlling
+ * tty for another session group!
+ */
+ if ((arg == 1) && suser()) {
+ /*
+ * Steal it away
+ */
+ struct task_struct *p;
+
+ read_lock(&tasklist_lock);
+ for_each_task(p)
+ if (p->tty == tty)
+ p->tty = NULL;
+ read_unlock(&tasklist_lock);
+ } else
+ return -EPERM;
+ }
+ task_lock(current);
+ current->tty = tty;
+ task_unlock(current);
+ current->tty_old_pgrp = 0;
+ tty->session = current->session;
+ tty->pgrp = current->pgrp;
+ return 0;
+}
+
+static int tiocgpgrp(struct tty_struct *tty, struct tty_struct *real_tty, pid_t *arg)
+{
+ /*
+ * (tty == real_tty) is a cheap way of
+ * testing if the tty is NOT a master pty.
+ */
+ if (tty == real_tty && current->tty != real_tty)
+ return -ENOTTY;
+ return put_user(real_tty->pgrp, arg);
+}
+
+static int tiocspgrp(struct tty_struct *tty, struct tty_struct *real_tty, pid_t *arg)
+{
+ pid_t pgrp;
+ int retval = tty_check_change(real_tty);
+
+ if (retval == -EIO)
+ return -ENOTTY;
+ if (retval)
+ return retval;
+ if (!current->tty ||
+ (current->tty != real_tty) ||
+ (real_tty->session != current->session))
+ return -ENOTTY;
+ if (get_user(pgrp, (pid_t *) arg))
+ return -EFAULT;
+ if (pgrp < 0)
+ return -EINVAL;
+ if (session_of_pgrp(pgrp) != current->session)
+ return -EPERM;
+ real_tty->pgrp = pgrp;
+ return 0;
+}
+
+static int tiocgsid(struct tty_struct *tty, struct tty_struct *real_tty, pid_t *arg)
+{
+ /*
+ * (tty == real_tty) is a cheap way of
+ * testing if the tty is NOT a master pty.
+ */
+ if (tty == real_tty && current->tty != real_tty)
+ return -ENOTTY;
+ if (real_tty->session <= 0)
+ return -ENOTTY;
+ return put_user(real_tty->session, arg);
+}
+
+static int tiocttygstruct(struct tty_struct *tty, struct tty_struct *arg)
+{
+ if (copy_to_user(arg, tty, sizeof(*arg)))
+ return -EFAULT;
+ return 0;
+}
+
+static int tiocsetd(struct tty_struct *tty, int *arg)
+{
+ int ldisc;
+
+ if (get_user(ldisc, arg))
+ return -EFAULT;
+ return tty_set_ldisc(tty, ldisc);
+}
+
+static int send_break(struct tty_struct *tty, int duration)
+{
+ set_current_state(TASK_INTERRUPTIBLE);
+
+ tty->driver.break_ctl(tty, -1);
+ if (!signal_pending(current))
+ schedule_timeout(duration);
+ tty->driver.break_ctl(tty, 0);
+ if (signal_pending(current))
+ return -EINTR;
+ return 0;
+}
+
+static int tty_generic_brk(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg)
+{
+ if (cmd == TCSBRK && arg)
+ {
+ /* tcdrain case */
+ int retval = tty_check_change(tty);
+ if (retval)
+ return retval;
+ tty_wait_until_sent(tty, 0);
+ if (signal_pending(current))
+ return -EINTR;
+ }
+ return 0;
+}
+
+/*
+ * Split this up, as gcc can choke on it otherwise..
+ */
+int tty_ioctl(struct inode * inode, struct file * file,
+ unsigned int cmd, unsigned long arg)
+{
+ struct tty_struct *tty, *real_tty;
+ int retval;
+
+ tty = (struct tty_struct *)file->private_data;
+ if (tty_paranoia_check(tty, inode->i_rdev, "tty_ioctl"))
+ return -EINVAL;
+
+ real_tty = tty;
+ if (tty->driver.type == TTY_DRIVER_TYPE_PTY &&
+ tty->driver.subtype == PTY_TYPE_MASTER)
+ real_tty = tty->link;
+
+ /*
+ * Break handling by driver
+ */
+ if (!tty->driver.break_ctl) {
+ switch(cmd) {
+ case TIOCSBRK:
+ case TIOCCBRK:
+ if (tty->driver.ioctl)
+ return tty->driver.ioctl(tty, file, cmd, arg);
+ return -EINVAL;
+
+ /* These two ioctl's always return success; even if */
+ /* the driver doesn't support them. */
+ case TCSBRK:
+ case TCSBRKP:
+ retval = -ENOIOCTLCMD;
+ if (tty->driver.ioctl)
+ retval = tty->driver.ioctl(tty, file, cmd, arg);
+ /* Not driver handled */
+ if (retval == -ENOIOCTLCMD)
+ retval = tty_generic_brk(tty, file, cmd, arg);
+ return retval;
+ }
+ }
+
+ /*
+ * Factor out some common prep work
+ */
+ switch (cmd) {
+ case TIOCSETD:
+ case TIOCSBRK:
+ case TIOCCBRK:
+ case TCSBRK:
+ case TCSBRKP:
+ retval = tty_check_change(tty);
+ if (retval)
+ return retval;
+ if (cmd != TIOCCBRK) {
+ tty_wait_until_sent(tty, 0);
+ if (signal_pending(current))
+ return -EINTR;
+ }
+ break;
+ }
+
+ switch (cmd) {
+ case TIOCSTI:
+ return tiocsti(tty, (char *)arg);
+ case TIOCGWINSZ:
+ return tiocgwinsz(tty, (struct winsize *) arg);
+ case TIOCSWINSZ:
+ return tiocswinsz(tty, real_tty, (struct winsize *) arg);
+ case TIOCCONS:
+ return real_tty!=tty ? -EINVAL : tioccons(inode, file);
+ case FIONBIO:
+ return fionbio(file, (int *) arg);
+ case TIOCEXCL:
+ set_bit(TTY_EXCLUSIVE, &tty->flags);
+ return 0;
+ case TIOCNXCL:
+ clear_bit(TTY_EXCLUSIVE, &tty->flags);
+ return 0;
+ case TIOCNOTTY:
+ if (current->tty != tty)
+ return -ENOTTY;
+ if (current->leader)
+ disassociate_ctty(0);
+ task_lock(current);
+ current->tty = NULL;
+ task_unlock(current);
+ return 0;
+ case TIOCSCTTY:
+ return tiocsctty(tty, arg);
+ case TIOCGPGRP:
+ return tiocgpgrp(tty, real_tty, (pid_t *) arg);
+ case TIOCSPGRP:
+ return tiocspgrp(tty, real_tty, (pid_t *) arg);
+ case TIOCGSID:
+ return tiocgsid(tty, real_tty, (pid_t *) arg);
+ case TIOCGETD:
+ return put_user(tty->ldisc.num, (int *) arg);
+ case TIOCSETD:
+ return tiocsetd(tty, (int *) arg);
+#ifdef CONFIG_VT
+ case TIOCLINUX:
+ return tioclinux(tty, arg);
+#endif
+ case TIOCTTYGSTRUCT:
+ return tiocttygstruct(tty, (struct tty_struct *) arg);
+
+ /*
+ * Break handling
+ */
+ case TIOCSBRK: /* Turn break on, unconditionally */
+ tty->driver.break_ctl(tty, -1);
+ return 0;
+
+ case TIOCCBRK: /* Turn break off, unconditionally */
+ tty->driver.break_ctl(tty, 0);
+ return 0;
+ case TCSBRK: /* SVID version: non-zero arg --> no break */
+ /*
+ * XXX is the above comment correct, or the
+ * code below correct? Is this ioctl used at
+ * all by anyone?
+ */
+ if (!arg)
+ return send_break(tty, HZ/4);
+ return 0;
+ case TCSBRKP: /* support for POSIX tcsendbreak() */
+ return send_break(tty, arg ? arg*(HZ/10) : HZ/4);
+ }
+ if (tty->driver.ioctl) {
+ int retval = (tty->driver.ioctl)(tty, file, cmd, arg);
+ if (retval != -ENOIOCTLCMD)
+ return retval;
+ }
+ if (tty->ldisc.ioctl) {
+ int retval = (tty->ldisc.ioctl)(tty, file, cmd, arg);
+ if (retval != -ENOIOCTLCMD)
+ return retval;
+ }
+ return -EINVAL;
+}
+
+
+/*
+ * This implements the "Secure Attention Key" --- the idea is to
+ * prevent trojan horses by killing all processes associated with this
+ * tty when the user hits the "Secure Attention Key". Required for
+ * super-paranoid applications --- see the Orange Book for more details.
+ *
+ * This code could be nicer; ideally it should send a HUP, wait a few
+ * seconds, then send a INT, and then a KILL signal. But you then
+ * have to coordinate with the init process, since all processes associated
+ * with the current tty must be dead before the new getty is allowed
+ * to spawn.
+ *
+ * Now, if it would be correct ;-/ The current code has a nasty hole -
+ * it doesn't catch files in flight. We may send the descriptor to ourselves
+ * via AF_UNIX socket, close it and later fetch from socket. FIXME.
+ *
+ * Nasty bug: do_SAK is being called in interrupt context. This can
+ * deadlock. We punt it up to process context. AKPM - 16Mar2001
+ */
+static void __do_SAK(void *arg)
+{
+#ifdef TTY_SOFT_SAK
+ tty_hangup(tty);
+#else
+ struct tty_struct *tty = arg;
+ struct task_struct *p;
+ int session;
+ int i;
+ struct file *filp;
+
+ if (!tty)
+ return;
+ session = tty->session;
+ if (tty->ldisc.flush_buffer)
+ tty->ldisc.flush_buffer(tty);
+ if (tty->driver.flush_buffer)
+ tty->driver.flush_buffer(tty);
+ read_lock(&tasklist_lock);
+ for_each_task(p) {
+ if ((p->tty == tty) ||
+ ((session > 0) && (p->session == session))) {
+ send_sig(SIGKILL, p, 1);
+ continue;
+ }
+ task_lock(p);
+ if (p->files) {
+ read_lock(&p->files->file_lock);
+ for (i=0; i < p->files->max_fds; i++) {
+ filp = fcheck_files(p->files, i);
+ if (filp && (filp->f_op == &tty_fops) &&
+ (filp->private_data == tty)) {
+ send_sig(SIGKILL, p, 1);
+ break;
+ }
+ }
+ read_unlock(&p->files->file_lock);
+ }
+ task_unlock(p);
+ }
+ read_unlock(&tasklist_lock);
+#endif
+}
+
+/*
+ * The tq handling here is a little racy - tty->SAK_tq may already be queued.
+ * But there's no mechanism to fix that without futzing with tqueue_lock.
+ * Fortunately we don't need to worry, because if ->SAK_tq is already queued,
+ * the values which we write to it will be identical to the values which it
+ * already has. --akpm
+ */
+void do_SAK(struct tty_struct *tty)
+{
+ if (!tty)
+ return;
+ PREPARE_TQUEUE(&tty->SAK_tq, __do_SAK, tty);
+ schedule_task(&tty->SAK_tq);
+}
+
+/*
+ * This routine is called out of the software interrupt to flush data
+ * from the flip buffer to the line discipline.
+ */
+static void flush_to_ldisc(void *private_)
+{
+ struct tty_struct *tty = (struct tty_struct *) private_;
+ unsigned char *cp;
+ char *fp;
+ int count;
+ unsigned long flags;
+
+ if (test_bit(TTY_DONT_FLIP, &tty->flags)) {
+ queue_task(&tty->flip.tqueue, &tq_timer);
+ return;
+ }
+ if (tty->flip.buf_num) {
+ cp = tty->flip.char_buf + TTY_FLIPBUF_SIZE;
+ fp = tty->flip.flag_buf + TTY_FLIPBUF_SIZE;
+ tty->flip.buf_num = 0;
+
+ save_flags(flags); cli();
+ tty->flip.char_buf_ptr = tty->flip.char_buf;
+ tty->flip.flag_buf_ptr = tty->flip.flag_buf;
+ } else {
+ cp = tty->flip.char_buf;
+ fp = tty->flip.flag_buf;
+ tty->flip.buf_num = 1;
+
+ save_flags(flags); cli();
+ tty->flip.char_buf_ptr = tty->flip.char_buf + TTY_FLIPBUF_SIZE;
+ tty->flip.flag_buf_ptr = tty->flip.flag_buf + TTY_FLIPBUF_SIZE;
+ }
+ count = tty->flip.count;
+ tty->flip.count = 0;
+ restore_flags(flags);
+
+ tty->ldisc.receive_buf(tty, cp, fp, count);
+}
+
+/*
+ * Routine which returns the baud rate of the tty
+ *
+ * Note that the baud_table needs to be kept in sync with the
+ * include/asm/termbits.h file.
+ */
+static int baud_table[] = {
+ 0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800,
+ 9600, 19200, 38400, 57600, 115200, 230400, 460800,
+#ifdef __sparc__
+ 76800, 153600, 307200, 614400, 921600
+#else
+ 500000, 576000, 921600, 1000000, 1152000, 1500000, 2000000,
+ 2500000, 3000000, 3500000, 4000000
+#endif
+};
+
+static int n_baud_table = sizeof(baud_table)/sizeof(int);
+
+int tty_get_baud_rate(struct tty_struct *tty)
+{
+ unsigned int cflag, i;
+
+ cflag = tty->termios->c_cflag;
+
+ i = cflag & CBAUD;
+ if (i & CBAUDEX) {
+ i &= ~CBAUDEX;
+ if (i < 1 || i+15 >= n_baud_table)
+ tty->termios->c_cflag &= ~CBAUDEX;
+ else
+ i += 15;
+ }
+ if (i==15 && tty->alt_speed) {
+ if (!tty->warned) {
+ printk(KERN_WARNING "Use of setserial/setrocket to "
+ "set SPD_* flags is deprecated\n");
+ tty->warned = 1;
+ }
+ return(tty->alt_speed);
+ }
+
+ return baud_table[i];
+}
+
+void tty_flip_buffer_push(struct tty_struct *tty)
+{
+ if (tty->low_latency)
+ flush_to_ldisc((void *) tty);
+ else
+ queue_task(&tty->flip.tqueue, &tq_timer);
+}
+
+/*
+ * This subroutine initializes a tty structure.
+ */
+static void initialize_tty_struct(struct tty_struct *tty)
+{
+ memset(tty, 0, sizeof(struct tty_struct));
+ tty->magic = TTY_MAGIC;
+ tty->ldisc = ldiscs[N_TTY];
+ tty->pgrp = -1;
+ tty->flip.char_buf_ptr = tty->flip.char_buf;
+ tty->flip.flag_buf_ptr = tty->flip.flag_buf;
+ tty->flip.tqueue.routine = flush_to_ldisc;
+ tty->flip.tqueue.data = tty;
+ init_MUTEX(&tty->flip.pty_sem);
+ init_waitqueue_head(&tty->write_wait);
+ init_waitqueue_head(&tty->read_wait);
+ tty->tq_hangup.routine = do_tty_hangup;
+ tty->tq_hangup.data = tty;
+ sema_init(&tty->atomic_read, 1);
+ sema_init(&tty->atomic_write, 1);
+ spin_lock_init(&tty->read_lock);
+ INIT_LIST_HEAD(&tty->tty_files);
+ INIT_TQUEUE(&tty->SAK_tq, 0, 0);
+}
+
+/*
+ * The default put_char routine if the driver did not define one.
+ */
+void tty_default_put_char(struct tty_struct *tty, unsigned char ch)
+{
+ tty->driver.write(tty, 0, &ch, 1);
+}
+
+/*
+ * Register a tty device described by <driver>, with minor number <minor>.
+ */
+void tty_register_devfs (struct tty_driver *driver, unsigned int flags, unsigned minor)
+{
+#ifdef CONFIG_DEVFS_FS
+ umode_t mode = S_IFCHR | S_IRUSR | S_IWUSR;
+ kdev_t device = MKDEV (driver->major, minor);
+ int idx = minor - driver->minor_start;
+ char buf[32];
+
+ switch (device) {
+ case TTY_DEV:
+ case PTMX_DEV:
+ mode |= S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;
+ break;
+ default:
+ if (driver->major == PTY_MASTER_MAJOR)
+ mode |= S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;
+ break;
+ }
+ if ( (minor < driver->minor_start) ||
+ (minor >= driver->minor_start + driver->num) ) {
+ printk(KERN_ERR "Attempt to register invalid minor number "
+ "with devfs (%d:%d).\n", (int)driver->major,(int)minor);
+ return;
+ }
+# ifdef CONFIG_UNIX98_PTYS
+ if ( (driver->major >= UNIX98_PTY_SLAVE_MAJOR) &&
+ (driver->major < UNIX98_PTY_SLAVE_MAJOR + UNIX98_NR_MAJORS) )
+ flags |= DEVFS_FL_CURRENT_OWNER;
+# endif
+ sprintf(buf, driver->name, idx + driver->name_base);
+ devfs_register (NULL, buf, flags | DEVFS_FL_DEFAULT,
+ driver->major, minor, mode, &tty_fops, NULL);
+#endif /* CONFIG_DEVFS_FS */
+}
+
+void tty_unregister_devfs (struct tty_driver *driver, unsigned minor)
+{
+#ifdef CONFIG_DEVFS_FS
+ void * handle;
+ int idx = minor - driver->minor_start;
+ char buf[32];
+
+ sprintf(buf, driver->name, idx + driver->name_base);
+ handle = devfs_find_handle (NULL, buf, driver->major, minor,
+ DEVFS_SPECIAL_CHR, 0);
+ devfs_unregister (handle);
+#endif /* CONFIG_DEVFS_FS */
+}
+
+EXPORT_SYMBOL(tty_register_devfs);
+EXPORT_SYMBOL(tty_unregister_devfs);
+
+/*
+ * Called by a tty driver to register itself.
+ */
+int tty_register_driver(struct tty_driver *driver)
+{
+ int error;
+ int i;
+
+ if (driver->flags & TTY_DRIVER_INSTALLED)
+ return 0;
+
+ error = devfs_register_chrdev(driver->major, driver->name, &tty_fops);
+ if (error < 0)
+ return error;
+ else if(driver->major == 0)
+ driver->major = error;
+
+ if (!driver->put_char)
+ driver->put_char = tty_default_put_char;
+
+ driver->prev = 0;
+ driver->next = tty_drivers;
+ if (tty_drivers) tty_drivers->prev = driver;
+ tty_drivers = driver;
+
+ if ( !(driver->flags & TTY_DRIVER_NO_DEVFS) ) {
+ for(i = 0; i < driver->num; i++)
+ tty_register_devfs(driver, 0, driver->minor_start + i);
+ }
+ proc_tty_register_driver(driver);
+ return error;
+}
+
+/*
+ * Called by a tty driver to unregister itself.
+ */
+int tty_unregister_driver(struct tty_driver *driver)
+{
+ int retval;
+ struct tty_driver *p;
+ int i, found = 0;
+ struct termios *tp;
+ const char *othername = NULL;
+
+ if (*driver->refcount)
+ return -EBUSY;
+
+ for (p = tty_drivers; p; p = p->next) {
+ if (p == driver)
+ found++;
+ else if (p->major == driver->major)
+ othername = p->name;
+ }
+
+ if (!found)
+ return -ENOENT;
+
+ if (othername == NULL) {
+ retval = devfs_unregister_chrdev(driver->major, driver->name);
+ if (retval)
+ return retval;
+ } else
+ devfs_register_chrdev(driver->major, othername, &tty_fops);
+
+ if (driver->prev)
+ driver->prev->next = driver->next;
+ else
+ tty_drivers = driver->next;
+
+ if (driver->next)
+ driver->next->prev = driver->prev;
+
+ /*
+ * Free the termios and termios_locked structures because
+ * we don't want to get memory leaks when modular tty
+ * drivers are removed from the kernel.
+ */
+ for (i = 0; i < driver->num; i++) {
+ tp = driver->termios[i];
+ if (tp) {
+ driver->termios[i] = NULL;
+ kfree(tp);
+ }
+ tp = driver->termios_locked[i];
+ if (tp) {
+ driver->termios_locked[i] = NULL;
+ kfree(tp);
+ }
+ tty_unregister_devfs(driver, driver->minor_start + i);
+ }
+ proc_tty_unregister_driver(driver);
+ return 0;
+}
+
+
+/*
+ * Initialize the console device. This is called *early*, so
+ * we can't necessarily depend on lots of kernel help here.
+ * Just do some early initializations, and do the complex setup
+ * later.
+ */
+void __init console_init(void)
+{
+ /* Setup the default TTY line discipline. */
+ memset(ldiscs, 0, sizeof(ldiscs));
+ (void) tty_register_ldisc(N_TTY, &tty_ldisc_N_TTY);
+
+ /*
+ * Set up the standard termios. Individual tty drivers may
+ * deviate from this; this is used as a template.
+ */
+ memset(&tty_std_termios, 0, sizeof(struct termios));
+ memcpy(tty_std_termios.c_cc, INIT_C_CC, NCCS);
+ tty_std_termios.c_iflag = ICRNL | IXON;
+ tty_std_termios.c_oflag = OPOST | ONLCR;
+ tty_std_termios.c_cflag = B38400 | CS8 | CREAD | HUPCL;
+ tty_std_termios.c_lflag = ISIG | ICANON | ECHO | ECHOE | ECHOK |
+ ECHOCTL | ECHOKE | IEXTEN;
+
+ /*
+ * set up the console device so that later boot sequences can
+ * inform about problems etc..
+ */
+#ifdef CONFIG_EARLY_PRINTK
+ disable_early_printk();
+#endif
+
+#ifdef CONFIG_VT
+ con_init();
+#endif
+
+#ifdef CONFIG_XEN_CONSOLE
+ xen_console_init();
+#endif
+#ifdef CONFIG_AU1000_SERIAL_CONSOLE
+ au1000_serial_console_init();
+#endif
+#ifdef CONFIG_SERIAL_CONSOLE
+#if (defined(CONFIG_8xx) || defined(CONFIG_8260))
+ console_8xx_init();
+#elif defined(CONFIG_MAC_SERIAL) && defined(CONFIG_SERIAL)
+ if (_machine == _MACH_Pmac)
+ mac_scc_console_init();
+ else
+ serial_console_init();
+#elif defined(CONFIG_MAC_SERIAL)
+ mac_scc_console_init();
+#elif defined(CONFIG_PARISC)
+ pdc_console_init();
+#elif defined(CONFIG_SERIAL)
+ serial_console_init();
+#endif /* CONFIG_8xx */
+#ifdef CONFIG_SGI_SERIAL
+ sgi_serial_console_init();
+#endif
+#if defined(CONFIG_MVME162_SCC) || defined(CONFIG_BVME6000_SCC) || defined(CONFIG_MVME147_SCC)
+ vme_scc_console_init();
+#endif
+#if defined(CONFIG_SERIAL167)
+ serial167_console_init();
+#endif
+#if defined(CONFIG_SH_SCI)
+ sci_console_init();
+#endif
+#endif
+#ifdef CONFIG_TN3270_CONSOLE
+ tub3270_con_init();
+#endif
+#ifdef CONFIG_TN3215
+ con3215_init();
+#endif
+#ifdef CONFIG_HWC
+ hwc_console_init();
+#endif
+#ifdef CONFIG_STDIO_CONSOLE
+ stdio_console_init();
+#endif
+#ifdef CONFIG_SERIAL_21285_CONSOLE
+ rs285_console_init();
+#endif
+#ifdef CONFIG_SERIAL_SA1100_CONSOLE
+ sa1100_rs_console_init();
+#endif
+#ifdef CONFIG_ARC_CONSOLE
+ arc_console_init();
+#endif
+#ifdef CONFIG_SERIAL_AMBA_CONSOLE
+ ambauart_console_init();
+#endif
+#ifdef CONFIG_SERIAL_TX3912_CONSOLE
+ tx3912_console_init();
+#endif
+#ifdef CONFIG_TXX927_SERIAL_CONSOLE
+ txx927_console_init();
+#endif
+#ifdef CONFIG_SIBYTE_SB1250_DUART_CONSOLE
+ sb1250_serial_console_init();
+#endif
+}
+
+static struct tty_driver dev_tty_driver, dev_syscons_driver;
+#ifdef CONFIG_UNIX98_PTYS
+static struct tty_driver dev_ptmx_driver;
+#endif
+#ifdef CONFIG_VT
+static struct tty_driver dev_console_driver;
+#endif
+
+/*
+ * Ok, now we can initialize the rest of the tty devices and can count
+ * on memory allocations, interrupts etc..
+ */
+void __init tty_init(void)
+{
+ /*
+ * dev_tty_driver and dev_console_driver are actually magic
+ * devices which get redirected at open time. Nevertheless,
+ * we register them so that register_chrdev is called
+ * appropriately.
+ */
+ memset(&dev_tty_driver, 0, sizeof(struct tty_driver));
+ dev_tty_driver.magic = TTY_DRIVER_MAGIC;
+ dev_tty_driver.driver_name = "/dev/tty";
+ dev_tty_driver.name = dev_tty_driver.driver_name + 5;
+ dev_tty_driver.name_base = 0;
+ dev_tty_driver.major = TTYAUX_MAJOR;
+ dev_tty_driver.minor_start = 0;
+ dev_tty_driver.num = 1;
+ dev_tty_driver.type = TTY_DRIVER_TYPE_SYSTEM;
+ dev_tty_driver.subtype = SYSTEM_TYPE_TTY;
+
+ if (tty_register_driver(&dev_tty_driver))
+ panic("Couldn't register /dev/tty driver\n");
+
+ dev_syscons_driver = dev_tty_driver;
+ dev_syscons_driver.driver_name = "/dev/console";
+ dev_syscons_driver.name = dev_syscons_driver.driver_name + 5;
+ dev_syscons_driver.major = TTYAUX_MAJOR;
+ dev_syscons_driver.minor_start = 1;
+ dev_syscons_driver.type = TTY_DRIVER_TYPE_SYSTEM;
+ dev_syscons_driver.subtype = SYSTEM_TYPE_SYSCONS;
+
+ if (tty_register_driver(&dev_syscons_driver))
+ panic("Couldn't register /dev/console driver\n");
+
+ /* console calls tty_register_driver() before kmalloc() works.
+ * Thus, we can't devfs_register() then. Do so now, instead.
+ */
+#ifdef CONFIG_VT
+ con_init_devfs();
+#endif
+
+#ifdef CONFIG_UNIX98_PTYS
+ dev_ptmx_driver = dev_tty_driver;
+ dev_ptmx_driver.driver_name = "/dev/ptmx";
+ dev_ptmx_driver.name = dev_ptmx_driver.driver_name + 5;
+ dev_ptmx_driver.major= MAJOR(PTMX_DEV);
+ dev_ptmx_driver.minor_start = MINOR(PTMX_DEV);
+ dev_ptmx_driver.type = TTY_DRIVER_TYPE_SYSTEM;
+ dev_ptmx_driver.subtype = SYSTEM_TYPE_SYSPTMX;
+
+ if (tty_register_driver(&dev_ptmx_driver))
+ panic("Couldn't register /dev/ptmx driver\n");
+#endif
+
+#ifdef CONFIG_VT
+ dev_console_driver = dev_tty_driver;
+ dev_console_driver.driver_name = "/dev/vc/0";
+ dev_console_driver.name = dev_console_driver.driver_name + 5;
+ dev_console_driver.major = TTY_MAJOR;
+ dev_console_driver.type = TTY_DRIVER_TYPE_SYSTEM;
+ dev_console_driver.subtype = SYSTEM_TYPE_CONSOLE;
+
+ if (tty_register_driver(&dev_console_driver))
+ panic("Couldn't register /dev/tty0 driver\n");
+
+ kbd_init();
+#endif
+
+#ifdef CONFIG_ESPSERIAL /* init ESP before rs, so rs doesn't see the port */
+ espserial_init();
+#endif
+#if defined(CONFIG_MVME162_SCC) || defined(CONFIG_BVME6000_SCC) || defined(CONFIG_MVME147_SCC)
+ vme_scc_init();
+#endif
+#ifdef CONFIG_SERIAL_TX3912
+ tx3912_rs_init();
+#endif
+#ifdef CONFIG_ROCKETPORT
+ rp_init();
+#endif
+#ifdef CONFIG_SERIAL167
+ serial167_init();
+#endif
+#ifdef CONFIG_CYCLADES
+ cy_init();
+#endif
+#ifdef CONFIG_STALLION
+ stl_init();
+#endif
+#ifdef CONFIG_ISTALLION
+ stli_init();
+#endif
+#ifdef CONFIG_DIGI
+ pcxe_init();
+#endif
+#ifdef CONFIG_DIGIEPCA
+ pc_init();
+#endif
+#ifdef CONFIG_SPECIALIX
+ specialix_init();
+#endif
+#if (defined(CONFIG_8xx) || defined(CONFIG_8260))
+ rs_8xx_init();
+#endif /* CONFIG_8xx */
+ pty_init();
+#ifdef CONFIG_MOXA_SMARTIO
+ mxser_init();
+#endif
+#ifdef CONFIG_MOXA_INTELLIO
+ moxa_init();
+#endif
+#ifdef CONFIG_VT
+ vcs_init();
+#endif
+#ifdef CONFIG_TN3270
+ tub3270_init();
+#endif
+#ifdef CONFIG_TN3215
+ tty3215_init();
+#endif
+#ifdef CONFIG_HWC
+ hwc_tty_init();
+#endif
+#ifdef CONFIG_A2232
+ a2232board_init();
+#endif
+}
--- /dev/null
+/*
+ * linux/fs/exec.c
+ *
+ * Copyright (C) 1991, 1992 Linus Torvalds
+ */
+
+/*
+ * #!-checking implemented by tytso.
+ */
+/*
+ * Demand-loading implemented 01.12.91 - no need to read anything but
+ * the header into memory. The inode of the executable is put into
+ * "current->executable", and page faults do the actual loading. Clean.
+ *
+ * Once more I can proudly say that linux stood up to being changed: it
+ * was less than 2 hours work to get demand-loading completely implemented.
+ *
+ * Demand loading changed July 1993 by Eric Youngdale. Use mmap instead,
+ * current->executable is only used by the procfs. This allows a dispatch
+ * table to check for several different types of binary formats. We keep
+ * trying until we recognize the file or we run out of supported binary
+ * formats.
+ */
+
+#include <linux/config.h>
+#include <linux/slab.h>
+#include <linux/file.h>
+#include <linux/mman.h>
+#include <linux/a.out.h>
+#include <linux/stat.h>
+#include <linux/fcntl.h>
+#include <linux/smp_lock.h>
+#include <linux/init.h>
+#include <linux/pagemap.h>
+#include <linux/highmem.h>
+#include <linux/spinlock.h>
+#include <linux/personality.h>
+#include <linux/swap.h>
+#include <linux/utsname.h>
+#define __NO_VERSION__
+#include <linux/module.h>
+
+#include <asm/uaccess.h>
+#include <asm/pgalloc.h>
+#include <asm/mmu_context.h>
+
+#ifdef CONFIG_KMOD
+#include <linux/kmod.h>
+#endif
+
+int core_uses_pid;
+char core_pattern[65] = "core";
+/* The maximal length of core_pattern is also specified in sysctl.c */
+
+static struct linux_binfmt *formats;
+static rwlock_t binfmt_lock = RW_LOCK_UNLOCKED;
+
+int register_binfmt(struct linux_binfmt * fmt)
+{
+ struct linux_binfmt ** tmp = &formats;
+
+ if (!fmt)
+ return -EINVAL;
+ if (fmt->next)
+ return -EBUSY;
+ write_lock(&binfmt_lock);
+ while (*tmp) {
+ if (fmt == *tmp) {
+ write_unlock(&binfmt_lock);
+ return -EBUSY;
+ }
+ tmp = &(*tmp)->next;
+ }
+ fmt->next = formats;
+ formats = fmt;
+ write_unlock(&binfmt_lock);
+ return 0;
+}
+
+int unregister_binfmt(struct linux_binfmt * fmt)
+{
+ struct linux_binfmt ** tmp = &formats;
+
+ write_lock(&binfmt_lock);
+ while (*tmp) {
+ if (fmt == *tmp) {
+ *tmp = fmt->next;
+ write_unlock(&binfmt_lock);
+ return 0;
+ }
+ tmp = &(*tmp)->next;
+ }
+ write_unlock(&binfmt_lock);
+ return -EINVAL;
+}
+
+static inline void put_binfmt(struct linux_binfmt * fmt)
+{
+ if (fmt->module)
+ __MOD_DEC_USE_COUNT(fmt->module);
+}
+
+/*
+ * Note that a shared library must be both readable and executable due to
+ * security reasons.
+ *
+ * Also note that we take the address to load from from the file itself.
+ */
+asmlinkage long sys_uselib(const char * library)
+{
+ struct file * file;
+ struct nameidata nd;
+ int error;
+
+ error = user_path_walk(library, &nd);
+ if (error)
+ goto out;
+
+ error = -EINVAL;
+ if (!S_ISREG(nd.dentry->d_inode->i_mode))
+ goto exit;
+
+ error = permission(nd.dentry->d_inode, MAY_READ | MAY_EXEC);
+ if (error)
+ goto exit;
+
+ file = dentry_open(nd.dentry, nd.mnt, O_RDONLY);
+ error = PTR_ERR(file);
+ if (IS_ERR(file))
+ goto out;
+
+ error = -ENOEXEC;
+ if(file->f_op && file->f_op->read) {
+ struct linux_binfmt * fmt;
+
+ read_lock(&binfmt_lock);
+ for (fmt = formats ; fmt ; fmt = fmt->next) {
+ if (!fmt->load_shlib)
+ continue;
+ if (!try_inc_mod_count(fmt->module))
+ continue;
+ read_unlock(&binfmt_lock);
+ error = fmt->load_shlib(file);
+ read_lock(&binfmt_lock);
+ put_binfmt(fmt);
+ if (error != -ENOEXEC)
+ break;
+ }
+ read_unlock(&binfmt_lock);
+ }
+ fput(file);
+out:
+ return error;
+exit:
+ path_release(&nd);
+ goto out;
+}
+
+/*
+ * count() counts the number of arguments/envelopes
+ */
+static int count(char ** argv, int max)
+{
+ int i = 0;
+
+ if (argv != NULL) {
+ for (;;) {
+ char * p;
+
+ if (get_user(p, argv))
+ return -EFAULT;
+ if (!p)
+ break;
+ argv++;
+ if(++i > max)
+ return -E2BIG;
+ }
+ }
+ return i;
+}
+
+/*
+ * 'copy_strings()' copies argument/envelope strings from user
+ * memory to free pages in kernel mem. These are in a format ready
+ * to be put directly into the top of new user memory.
+ */
+int copy_strings(int argc,char ** argv, struct linux_binprm *bprm)
+{
+ struct page *kmapped_page = NULL;
+ char *kaddr = NULL;
+ int ret;
+
+ while (argc-- > 0) {
+ char *str;
+ int len;
+ unsigned long pos;
+
+ if (get_user(str, argv+argc) ||
+ !(len = strnlen_user(str, bprm->p))) {
+ ret = -EFAULT;
+ goto out;
+ }
+
+ if (bprm->p < len) {
+ ret = -E2BIG;
+ goto out;
+ }
+
+ bprm->p -= len;
+ /* XXX: add architecture specific overflow check here. */
+ pos = bprm->p;
+
+ while (len > 0) {
+ int i, new, err;
+ int offset, bytes_to_copy;
+ struct page *page;
+
+ offset = pos % PAGE_SIZE;
+ i = pos/PAGE_SIZE;
+ page = bprm->page[i];
+ new = 0;
+ if (!page) {
+ page = alloc_page(GFP_HIGHUSER);
+ bprm->page[i] = page;
+ if (!page) {
+ ret = -ENOMEM;
+ goto out;
+ }
+ new = 1;
+ }
+
+ if (page != kmapped_page) {
+ if (kmapped_page)
+ kunmap(kmapped_page);
+ kmapped_page = page;
+ kaddr = kmap(kmapped_page);
+ }
+ if (new && offset)
+ memset(kaddr, 0, offset);
+ bytes_to_copy = PAGE_SIZE - offset;
+ if (bytes_to_copy > len) {
+ bytes_to_copy = len;
+ if (new)
+ memset(kaddr+offset+len, 0,
+ PAGE_SIZE-offset-len);
+ }
+ err = copy_from_user(kaddr+offset, str, bytes_to_copy);
+ if (err) {
+ ret = -EFAULT;
+ goto out;
+ }
+
+ pos += bytes_to_copy;
+ str += bytes_to_copy;
+ len -= bytes_to_copy;
+ }
+ }
+ ret = 0;
+out:
+ if (kmapped_page)
+ kunmap(kmapped_page);
+ return ret;
+}
+
+/*
+ * Like copy_strings, but get argv and its values from kernel memory.
+ */
+int copy_strings_kernel(int argc,char ** argv, struct linux_binprm *bprm)
+{
+ int r;
+ mm_segment_t oldfs = get_fs();
+ set_fs(KERNEL_DS);
+ r = copy_strings(argc, argv, bprm);
+ set_fs(oldfs);
+ return r;
+}
+
+/*
+ * This routine is used to map in a page into an address space: needed by
+ * execve() for the initial stack and environment pages.
+ *
+ * tsk->mmap_sem is held for writing.
+ */
+void put_dirty_page(struct task_struct * tsk, struct page *page, unsigned long address)
+{
+ pgd_t * pgd;
+ pmd_t * pmd;
+ pte_t * pte;
+
+ if (page_count(page) != 1)
+ printk(KERN_ERR "mem_map disagrees with %p at %08lx\n", page, address);
+ pgd = pgd_offset(tsk->mm, address);
+
+ spin_lock(&tsk->mm->page_table_lock);
+ pmd = pmd_alloc(tsk->mm, pgd, address);
+ if (!pmd)
+ goto out;
+ pte = pte_alloc(tsk->mm, pmd, address);
+ if (!pte)
+ goto out;
+ if (!pte_none(*pte))
+ goto out;
+ lru_cache_add(page);
+ flush_dcache_page(page);
+ flush_page_to_ram(page);
+ set_pte(pte, pte_mkdirty(pte_mkwrite(mk_pte(page, PAGE_COPY))));
+ XENO_flush_page_update_queue();
+ tsk->mm->rss++;
+ spin_unlock(&tsk->mm->page_table_lock);
+
+ /* no need for flush_tlb */
+ return;
+out:
+ spin_unlock(&tsk->mm->page_table_lock);
+ __free_page(page);
+ force_sig(SIGKILL, tsk);
+ return;
+}
+
+int setup_arg_pages(struct linux_binprm *bprm)
+{
+ unsigned long stack_base;
+ struct vm_area_struct *mpnt;
+ int i;
+
+ stack_base = STACK_TOP - MAX_ARG_PAGES*PAGE_SIZE;
+
+ bprm->p += stack_base;
+ if (bprm->loader)
+ bprm->loader += stack_base;
+ bprm->exec += stack_base;
+
+ mpnt = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL);
+ if (!mpnt)
+ return -ENOMEM;
+
+ down_write(¤t->mm->mmap_sem);
+ {
+ mpnt->vm_mm = current->mm;
+ mpnt->vm_start = PAGE_MASK & (unsigned long) bprm->p;
+ mpnt->vm_end = STACK_TOP;
+ mpnt->vm_page_prot = PAGE_COPY;
+ mpnt->vm_flags = VM_STACK_FLAGS;
+ mpnt->vm_ops = NULL;
+ mpnt->vm_pgoff = 0;
+ mpnt->vm_file = NULL;
+ mpnt->vm_private_data = (void *) 0;
+ insert_vm_struct(current->mm, mpnt);
+ current->mm->total_vm = (mpnt->vm_end - mpnt->vm_start) >> PAGE_SHIFT;
+ }
+
+ for (i = 0 ; i < MAX_ARG_PAGES ; i++) {
+ struct page *page = bprm->page[i];
+ if (page) {
+ bprm->page[i] = NULL;
+ put_dirty_page(current,page,stack_base);
+ }
+ stack_base += PAGE_SIZE;
+ }
+ up_write(¤t->mm->mmap_sem);
+
+ return 0;
+}
+
+struct file *open_exec(const char *name)
+{
+ struct nameidata nd;
+ struct inode *inode;
+ struct file *file;
+ int err = 0;
+
+ err = path_lookup(name, LOOKUP_FOLLOW|LOOKUP_POSITIVE, &nd);
+ file = ERR_PTR(err);
+ if (!err) {
+ inode = nd.dentry->d_inode;
+ file = ERR_PTR(-EACCES);
+ if (!(nd.mnt->mnt_flags & MNT_NOEXEC) &&
+ S_ISREG(inode->i_mode)) {
+ int err = permission(inode, MAY_EXEC);
+ if (!err && !(inode->i_mode & 0111))
+ err = -EACCES;
+ file = ERR_PTR(err);
+ if (!err) {
+ file = dentry_open(nd.dentry, nd.mnt, O_RDONLY);
+ if (!IS_ERR(file)) {
+ err = deny_write_access(file);
+ if (err) {
+ fput(file);
+ file = ERR_PTR(err);
+ }
+ }
+out:
+ return file;
+ }
+ }
+ path_release(&nd);
+ }
+ goto out;
+}
+
+int kernel_read(struct file *file, unsigned long offset,
+ char * addr, unsigned long count)
+{
+ mm_segment_t old_fs;
+ loff_t pos = offset;
+ int result = -ENOSYS;
+
+ if (!file->f_op->read)
+ goto fail;
+ old_fs = get_fs();
+ set_fs(get_ds());
+ result = file->f_op->read(file, addr, count, &pos);
+ set_fs(old_fs);
+fail:
+ return result;
+}
+
+static int exec_mmap(void)
+{
+ struct mm_struct * mm, * old_mm;
+
+ old_mm = current->mm;
+ if (old_mm && atomic_read(&old_mm->mm_users) == 1) {
+ mm_release();
+ exit_mmap(old_mm);
+ return 0;
+ }
+
+ mm = mm_alloc();
+ if (mm) {
+ struct mm_struct *active_mm;
+
+ if (init_new_context(current, mm)) {
+ mmdrop(mm);
+ return -ENOMEM;
+ }
+
+ /* Add it to the list of mm's */
+ spin_lock(&mmlist_lock);
+ list_add(&mm->mmlist, &init_mm.mmlist);
+ mmlist_nr++;
+ spin_unlock(&mmlist_lock);
+
+ task_lock(current);
+ active_mm = current->active_mm;
+ current->mm = mm;
+ current->active_mm = mm;
+ task_unlock(current);
+ activate_mm(active_mm, mm);
+ mm_release();
+ if (old_mm) {
+ if (active_mm != old_mm) BUG();
+ mmput(old_mm);
+ return 0;
+ }
+ mmdrop(active_mm);
+ return 0;
+ }
+ return -ENOMEM;
+}
+
+/*
+ * This function makes sure the current process has its own signal table,
+ * so that flush_signal_handlers can later reset the handlers without
+ * disturbing other processes. (Other processes might share the signal
+ * table via the CLONE_SIGNAL option to clone().)
+ */
+
+static inline int make_private_signals(void)
+{
+ struct signal_struct * newsig;
+
+ if (atomic_read(¤t->sig->count) <= 1)
+ return 0;
+ newsig = kmem_cache_alloc(sigact_cachep, GFP_KERNEL);
+ if (newsig == NULL)
+ return -ENOMEM;
+ spin_lock_init(&newsig->siglock);
+ atomic_set(&newsig->count, 1);
+ memcpy(newsig->action, current->sig->action, sizeof(newsig->action));
+ spin_lock_irq(¤t->sigmask_lock);
+ current->sig = newsig;
+ spin_unlock_irq(¤t->sigmask_lock);
+ return 0;
+}
+
+/*
+ * If make_private_signals() made a copy of the signal table, decrement the
+ * refcount of the original table, and free it if necessary.
+ * We don't do that in make_private_signals() so that we can back off
+ * in flush_old_exec() if an error occurs after calling make_private_signals().
+ */
+
+static inline void release_old_signals(struct signal_struct * oldsig)
+{
+ if (current->sig == oldsig)
+ return;
+ if (atomic_dec_and_test(&oldsig->count))
+ kmem_cache_free(sigact_cachep, oldsig);
+}
+
+/*
+ * These functions flushes out all traces of the currently running executable
+ * so that a new one can be started
+ */
+
+static inline void flush_old_files(struct files_struct * files)
+{
+ long j = -1;
+
+ write_lock(&files->file_lock);
+ for (;;) {
+ unsigned long set, i;
+
+ j++;
+ i = j * __NFDBITS;
+ if (i >= files->max_fds || i >= files->max_fdset)
+ break;
+ set = files->close_on_exec->fds_bits[j];
+ if (!set)
+ continue;
+ files->close_on_exec->fds_bits[j] = 0;
+ write_unlock(&files->file_lock);
+ for ( ; set ; i++,set >>= 1) {
+ if (set & 1) {
+ sys_close(i);
+ }
+ }
+ write_lock(&files->file_lock);
+
+ }
+ write_unlock(&files->file_lock);
+}
+
+/*
+ * An execve() will automatically "de-thread" the process.
+ * Note: we don't have to hold the tasklist_lock to test
+ * whether we migth need to do this. If we're not part of
+ * a thread group, there is no way we can become one
+ * dynamically. And if we are, we only need to protect the
+ * unlink - even if we race with the last other thread exit,
+ * at worst the list_del_init() might end up being a no-op.
+ */
+static inline void de_thread(struct task_struct *tsk)
+{
+ if (!list_empty(&tsk->thread_group)) {
+ write_lock_irq(&tasklist_lock);
+ list_del_init(&tsk->thread_group);
+ write_unlock_irq(&tasklist_lock);
+ }
+
+ /* Minor oddity: this might stay the same. */
+ tsk->tgid = tsk->pid;
+}
+
+int flush_old_exec(struct linux_binprm * bprm)
+{
+ char * name;
+ int i, ch, retval;
+ struct signal_struct * oldsig;
+
+ /*
+ * Make sure we have a private signal table
+ */
+ oldsig = current->sig;
+ retval = make_private_signals();
+ if (retval) goto flush_failed;
+
+ /*
+ * Release all of the old mmap stuff
+ */
+ retval = exec_mmap();
+ if (retval) goto mmap_failed;
+
+ /* This is the point of no return */
+ release_old_signals(oldsig);
+
+ current->sas_ss_sp = current->sas_ss_size = 0;
+
+ if (current->euid == current->uid && current->egid == current->gid) {
+ current->mm->dumpable = 1;
+ current->task_dumpable = 1;
+ }
+ name = bprm->filename;
+ for (i=0; (ch = *(name++)) != '\0';) {
+ if (ch == '/')
+ i = 0;
+ else
+ if (i < 15)
+ current->comm[i++] = ch;
+ }
+ current->comm[i] = '\0';
+
+ flush_thread();
+
+ de_thread(current);
+
+ if (bprm->e_uid != current->euid || bprm->e_gid != current->egid ||
+ permission(bprm->file->f_dentry->d_inode,MAY_READ))
+ current->mm->dumpable = 0;
+
+ /* An exec changes our domain. We are no longer part of the thread
+ group */
+
+ current->self_exec_id++;
+
+ flush_signal_handlers(current);
+ flush_old_files(current->files);
+
+ return 0;
+
+mmap_failed:
+flush_failed:
+ spin_lock_irq(¤t->sigmask_lock);
+ if (current->sig != oldsig) {
+ kmem_cache_free(sigact_cachep, current->sig);
+ current->sig = oldsig;
+ }
+ spin_unlock_irq(¤t->sigmask_lock);
+ return retval;
+}
+
+/*
+ * We mustn't allow tracing of suid binaries, unless
+ * the tracer has the capability to trace anything..
+ */
+static inline int must_not_trace_exec(struct task_struct * p)
+{
+ return (p->ptrace & PT_PTRACED) && !(p->ptrace & PT_PTRACE_CAP);
+}
+
+/*
+ * Fill the binprm structure from the inode.
+ * Check permissions, then read the first 128 (BINPRM_BUF_SIZE) bytes
+ */
+int prepare_binprm(struct linux_binprm *bprm)
+{
+ int mode;
+ struct inode * inode = bprm->file->f_dentry->d_inode;
+
+ mode = inode->i_mode;
+ /*
+ * Check execute perms again - if the caller has CAP_DAC_OVERRIDE,
+ * vfs_permission lets a non-executable through
+ */
+ if (!(mode & 0111)) /* with at least _one_ execute bit set */
+ return -EACCES;
+ if (bprm->file->f_op == NULL)
+ return -EACCES;
+
+ bprm->e_uid = current->euid;
+ bprm->e_gid = current->egid;
+
+ if(!(bprm->file->f_vfsmnt->mnt_flags & MNT_NOSUID)) {
+ /* Set-uid? */
+ if (mode & S_ISUID)
+ bprm->e_uid = inode->i_uid;
+
+ /* Set-gid? */
+ /*
+ * If setgid is set but no group execute bit then this
+ * is a candidate for mandatory locking, not a setgid
+ * executable.
+ */
+ if ((mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP))
+ bprm->e_gid = inode->i_gid;
+ }
+
+ /* We don't have VFS support for capabilities yet */
+ cap_clear(bprm->cap_inheritable);
+ cap_clear(bprm->cap_permitted);
+ cap_clear(bprm->cap_effective);
+
+ /* To support inheritance of root-permissions and suid-root
+ * executables under compatibility mode, we raise all three
+ * capability sets for the file.
+ *
+ * If only the real uid is 0, we only raise the inheritable
+ * and permitted sets of the executable file.
+ */
+
+ if (!issecure(SECURE_NOROOT)) {
+ if (bprm->e_uid == 0 || current->uid == 0) {
+ cap_set_full(bprm->cap_inheritable);
+ cap_set_full(bprm->cap_permitted);
+ }
+ if (bprm->e_uid == 0)
+ cap_set_full(bprm->cap_effective);
+ }
+
+ memset(bprm->buf,0,BINPRM_BUF_SIZE);
+ return kernel_read(bprm->file,0,bprm->buf,BINPRM_BUF_SIZE);
+}
+
+/*
+ * This function is used to produce the new IDs and capabilities
+ * from the old ones and the file's capabilities.
+ *
+ * The formula used for evolving capabilities is:
+ *
+ * pI' = pI
+ * (***) pP' = (fP & X) | (fI & pI)
+ * pE' = pP' & fE [NB. fE is 0 or ~0]
+ *
+ * I=Inheritable, P=Permitted, E=Effective // p=process, f=file
+ * ' indicates post-exec(), and X is the global 'cap_bset'.
+ *
+ */
+
+void compute_creds(struct linux_binprm *bprm)
+{
+ kernel_cap_t new_permitted, working;
+ int do_unlock = 0;
+
+ new_permitted = cap_intersect(bprm->cap_permitted, cap_bset);
+ working = cap_intersect(bprm->cap_inheritable,
+ current->cap_inheritable);
+ new_permitted = cap_combine(new_permitted, working);
+
+ if (bprm->e_uid != current->uid || bprm->e_gid != current->gid ||
+ !cap_issubset(new_permitted, current->cap_permitted)) {
+ current->mm->dumpable = 0;
+
+ lock_kernel();
+ if (must_not_trace_exec(current)
+ || atomic_read(¤t->fs->count) > 1
+ || atomic_read(¤t->files->count) > 1
+ || atomic_read(¤t->sig->count) > 1) {
+ if(!capable(CAP_SETUID)) {
+ bprm->e_uid = current->uid;
+ bprm->e_gid = current->gid;
+ }
+ if(!capable(CAP_SETPCAP)) {
+ new_permitted = cap_intersect(new_permitted,
+ current->cap_permitted);
+ }
+ }
+ do_unlock = 1;
+ }
+
+
+ /* For init, we want to retain the capabilities set
+ * in the init_task struct. Thus we skip the usual
+ * capability rules */
+ if (current->pid != 1) {
+ current->cap_permitted = new_permitted;
+ current->cap_effective =
+ cap_intersect(new_permitted, bprm->cap_effective);
+ }
+
+ /* AUD: Audit candidate if current->cap_effective is set */
+
+ current->suid = current->euid = current->fsuid = bprm->e_uid;
+ current->sgid = current->egid = current->fsgid = bprm->e_gid;
+
+ if(do_unlock)
+ unlock_kernel();
+ current->keep_capabilities = 0;
+}
+
+
+void remove_arg_zero(struct linux_binprm *bprm)
+{
+ if (bprm->argc) {
+ unsigned long offset;
+ char * kaddr;
+ struct page *page;
+
+ offset = bprm->p % PAGE_SIZE;
+ goto inside;
+
+ while (bprm->p++, *(kaddr+offset++)) {
+ if (offset != PAGE_SIZE)
+ continue;
+ offset = 0;
+ kunmap(page);
+inside:
+ page = bprm->page[bprm->p/PAGE_SIZE];
+ kaddr = kmap(page);
+ }
+ kunmap(page);
+ bprm->argc--;
+ }
+}
+
+/*
+ * cycle the list of binary formats handler, until one recognizes the image
+ */
+int search_binary_handler(struct linux_binprm *bprm,struct pt_regs *regs)
+{
+ int try,retval=0;
+ struct linux_binfmt *fmt;
+#ifdef __alpha__
+ /* handle /sbin/loader.. */
+ {
+ struct exec * eh = (struct exec *) bprm->buf;
+
+ if (!bprm->loader && eh->fh.f_magic == 0x183 &&
+ (eh->fh.f_flags & 0x3000) == 0x3000)
+ {
+ struct file * file;
+ unsigned long loader;
+
+ allow_write_access(bprm->file);
+ fput(bprm->file);
+ bprm->file = NULL;
+
+ loader = PAGE_SIZE*MAX_ARG_PAGES-sizeof(void *);
+
+ file = open_exec("/sbin/loader");
+ retval = PTR_ERR(file);
+ if (IS_ERR(file))
+ return retval;
+
+ /* Remember if the application is TASO. */
+ bprm->sh_bang = eh->ah.entry < 0x100000000;
+
+ bprm->file = file;
+ bprm->loader = loader;
+ retval = prepare_binprm(bprm);
+ if (retval<0)
+ return retval;
+ /* should call search_binary_handler recursively here,
+ but it does not matter */
+ }
+ }
+#endif
+ /* kernel module loader fixup */
+ /* so we don't try to load run modprobe in kernel space. */
+ set_fs(USER_DS);
+ for (try=0; try<2; try++) {
+ read_lock(&binfmt_lock);
+ for (fmt = formats ; fmt ; fmt = fmt->next) {
+ int (*fn)(struct linux_binprm *, struct pt_regs *) = fmt->load_binary;
+ if (!fn)
+ continue;
+ if (!try_inc_mod_count(fmt->module))
+ continue;
+ read_unlock(&binfmt_lock);
+ retval = fn(bprm, regs);
+ if (retval >= 0) {
+ put_binfmt(fmt);
+ allow_write_access(bprm->file);
+ if (bprm->file)
+ fput(bprm->file);
+ bprm->file = NULL;
+ current->did_exec = 1;
+ return retval;
+ }
+ read_lock(&binfmt_lock);
+ put_binfmt(fmt);
+ if (retval != -ENOEXEC)
+ break;
+ if (!bprm->file) {
+ read_unlock(&binfmt_lock);
+ return retval;
+ }
+ }
+ read_unlock(&binfmt_lock);
+ if (retval != -ENOEXEC) {
+ break;
+#ifdef CONFIG_KMOD
+ }else{
+#define printable(c) (((c)=='\t') || ((c)=='\n') || (0x20<=(c) && (c)<=0x7e))
+ char modname[20];
+ if (printable(bprm->buf[0]) &&
+ printable(bprm->buf[1]) &&
+ printable(bprm->buf[2]) &&
+ printable(bprm->buf[3]))
+ break; /* -ENOEXEC */
+ sprintf(modname, "binfmt-%04x", *(unsigned short *)(&bprm->buf[2]));
+ request_module(modname);
+#endif
+ }
+ }
+ return retval;
+}
+
+
+/*
+ * sys_execve() executes a new program.
+ */
+int do_execve(char * filename, char ** argv, char ** envp, struct pt_regs * regs)
+{
+ struct linux_binprm bprm;
+ struct file *file;
+ int retval;
+ int i;
+
+ file = open_exec(filename);
+
+ retval = PTR_ERR(file);
+ if (IS_ERR(file))
+ return retval;
+
+ bprm.p = PAGE_SIZE*MAX_ARG_PAGES-sizeof(void *);
+ memset(bprm.page, 0, MAX_ARG_PAGES*sizeof(bprm.page[0]));
+
+ bprm.file = file;
+ bprm.filename = filename;
+ bprm.sh_bang = 0;
+ bprm.loader = 0;
+ bprm.exec = 0;
+ if ((bprm.argc = count(argv, bprm.p / sizeof(void *))) < 0) {
+ allow_write_access(file);
+ fput(file);
+ return bprm.argc;
+ }
+
+ if ((bprm.envc = count(envp, bprm.p / sizeof(void *))) < 0) {
+ allow_write_access(file);
+ fput(file);
+ return bprm.envc;
+ }
+
+ retval = prepare_binprm(&bprm);
+ if (retval < 0)
+ goto out;
+
+ retval = copy_strings_kernel(1, &bprm.filename, &bprm);
+ if (retval < 0)
+ goto out;
+
+ bprm.exec = bprm.p;
+ retval = copy_strings(bprm.envc, envp, &bprm);
+ if (retval < 0)
+ goto out;
+
+ retval = copy_strings(bprm.argc, argv, &bprm);
+ if (retval < 0)
+ goto out;
+
+ retval = search_binary_handler(&bprm,regs);
+ if (retval >= 0)
+ /* execve success */
+ return retval;
+
+out:
+ /* Something went wrong, return the inode and free the argument pages*/
+ allow_write_access(bprm.file);
+ if (bprm.file)
+ fput(bprm.file);
+
+ for (i = 0 ; i < MAX_ARG_PAGES ; i++) {
+ struct page * page = bprm.page[i];
+ if (page)
+ __free_page(page);
+ }
+
+ return retval;
+}
+
+void set_binfmt(struct linux_binfmt *new)
+{
+ struct linux_binfmt *old = current->binfmt;
+ if (new && new->module)
+ __MOD_INC_USE_COUNT(new->module);
+ current->binfmt = new;
+ if (old && old->module)
+ __MOD_DEC_USE_COUNT(old->module);
+}
+
+#define CORENAME_MAX_SIZE 64
+
+/* format_corename will inspect the pattern parameter, and output a
+ * name into corename, which must have space for at least
+ * CORENAME_MAX_SIZE bytes plus one byte for the zero terminator.
+ */
+void format_corename(char *corename, const char *pattern, long signr)
+{
+ const char *pat_ptr = pattern;
+ char *out_ptr = corename;
+ char *const out_end = corename + CORENAME_MAX_SIZE;
+ int rc;
+ int pid_in_pattern = 0;
+
+ /* Repeat as long as we have more pattern to process and more output
+ space */
+ while (*pat_ptr) {
+ if (*pat_ptr != '%') {
+ if (out_ptr == out_end)
+ goto out;
+ *out_ptr++ = *pat_ptr++;
+ } else {
+ switch (*++pat_ptr) {
+ case 0:
+ goto out;
+ /* Double percent, output one percent */
+ case '%':
+ if (out_ptr == out_end)
+ goto out;
+ *out_ptr++ = '%';
+ break;
+ /* pid */
+ case 'p':
+ pid_in_pattern = 1;
+ rc = snprintf(out_ptr, out_end - out_ptr,
+ "%d", current->pid);
+ if (rc > out_end - out_ptr)
+ goto out;
+ out_ptr += rc;
+ break;
+ /* uid */
+ case 'u':
+ rc = snprintf(out_ptr, out_end - out_ptr,
+ "%d", current->uid);
+ if (rc > out_end - out_ptr)
+ goto out;
+ out_ptr += rc;
+ break;
+ /* gid */
+ case 'g':
+ rc = snprintf(out_ptr, out_end - out_ptr,
+ "%d", current->gid);
+ if (rc > out_end - out_ptr)
+ goto out;
+ out_ptr += rc;
+ break;
+ /* signal that caused the coredump */
+ case 's':
+ rc = snprintf(out_ptr, out_end - out_ptr,
+ "%ld", signr);
+ if (rc > out_end - out_ptr)
+ goto out;
+ out_ptr += rc;
+ break;
+ /* UNIX time of coredump */
+ case 't': {
+ struct timeval tv;
+ do_gettimeofday(&tv);
+ rc = snprintf(out_ptr, out_end - out_ptr,
+ "%ld", tv.tv_sec);
+ if (rc > out_end - out_ptr)
+ goto out;
+ out_ptr += rc;
+ break;
+ }
+ /* hostname */
+ case 'h':
+ down_read(&uts_sem);
+ rc = snprintf(out_ptr, out_end - out_ptr,
+ "%s", system_utsname.nodename);
+ up_read(&uts_sem);
+ if (rc > out_end - out_ptr)
+ goto out;
+ out_ptr += rc;
+ break;
+ /* executable */
+ case 'e':
+ rc = snprintf(out_ptr, out_end - out_ptr,
+ "%s", current->comm);
+ if (rc > out_end - out_ptr)
+ goto out;
+ out_ptr += rc;
+ break;
+ default:
+ break;
+ }
+ ++pat_ptr;
+ }
+ }
+ /* Backward compatibility with core_uses_pid:
+ *
+ * If core_pattern does not include a %p (as is the default)
+ * and core_uses_pid is set, then .%pid will be appended to
+ * the filename */
+ if (!pid_in_pattern
+ && (core_uses_pid || atomic_read(¤t->mm->mm_users) != 1)) {
+ rc = snprintf(out_ptr, out_end - out_ptr,
+ ".%d", current->pid);
+ if (rc > out_end - out_ptr)
+ goto out;
+ out_ptr += rc;
+ }
+ out:
+ *out_ptr = 0;
+}
+
+int do_coredump(long signr, struct pt_regs * regs)
+{
+ struct linux_binfmt * binfmt;
+ char corename[CORENAME_MAX_SIZE + 1];
+ struct file * file;
+ struct inode * inode;
+ int retval = 0;
+
+ lock_kernel();
+ binfmt = current->binfmt;
+ if (!binfmt || !binfmt->core_dump)
+ goto fail;
+ if (!is_dumpable(current))
+ goto fail;
+ current->mm->dumpable = 0;
+ if (current->rlim[RLIMIT_CORE].rlim_cur < binfmt->min_coredump)
+ goto fail;
+
+ format_corename(corename, core_pattern, signr);
+ file = filp_open(corename, O_CREAT | 2 | O_NOFOLLOW, 0600);
+ if (IS_ERR(file))
+ goto fail;
+ inode = file->f_dentry->d_inode;
+ if (inode->i_nlink > 1)
+ goto close_fail; /* multiple links - don't dump */
+ if (d_unhashed(file->f_dentry))
+ goto close_fail;
+
+ if (!S_ISREG(inode->i_mode))
+ goto close_fail;
+ if (!file->f_op)
+ goto close_fail;
+ if (!file->f_op->write)
+ goto close_fail;
+ if (do_truncate(file->f_dentry, 0) != 0)
+ goto close_fail;
+
+ retval = binfmt->core_dump(signr, regs, file);
+
+close_fail:
+ filp_close(file, NULL);
+fail:
+ unlock_kernel();
+ return retval;
+}
--- /dev/null
+/*
+ * include/asm-i386/bugs.h
+ *
+ * Copyright (C) 1994 Linus Torvalds
+ *
+ * Cyrix stuff, June 1998 by:
+ * - Rafael R. Reilova (moved everything from head.S),
+ * <rreilova@ececs.uc.edu>
+ * - Channing Corn (tests & fixes),
+ * - Andrew D. Balsa (code cleanup).
+ *
+ * Pentium III FXSR, SSE support
+ * Gareth Hughes <gareth@valinux.com>, May 2000
+ */
+
+/*
+ * This is included by init/main.c to check for architecture-dependent bugs.
+ *
+ * Needs:
+ * void check_bugs(void);
+ */
+
+#include <linux/config.h>
+#include <asm/processor.h>
+#include <asm/i387.h>
+#include <asm/msr.h>
+
+
+static void __init check_fpu(void)
+{
+ boot_cpu_data.fdiv_bug = 0;
+}
+
+static void __init check_hlt(void)
+{
+ boot_cpu_data.hlt_works_ok = 1;
+}
+
+static void __init check_bugs(void)
+{
+ extern void __init boot_init_fpu(void);
+
+ identify_cpu(&boot_cpu_data);
+ boot_init_fpu();
+#ifndef CONFIG_SMP
+ printk("CPU: ");
+ print_cpu_info(&boot_cpu_data);
+#endif
+ check_fpu();
+ check_hlt();
+ system_utsname.machine[1] = '0' +
+ (boot_cpu_data.x86 > 6 ? 6 : boot_cpu_data.x86);
+}
--- /dev/null
+#ifndef __ARCH_DESC_H
+#define __ARCH_DESC_H
+
+#include <asm/ldt.h>
+
+#ifndef __ASSEMBLY__
+
+struct desc_struct {
+ unsigned long a,b;
+};
+
+struct Xgt_desc_struct {
+ unsigned short size;
+ unsigned long address __attribute__((packed));
+};
+
+extern struct desc_struct default_ldt[];
+
+static inline void clear_LDT(void)
+{
+ queue_set_ldt((unsigned long)&default_ldt[0], 5);
+}
+
+static inline void load_LDT(struct mm_struct *mm)
+{
+ void *segments = mm->context.segments;
+ int count = LDT_ENTRIES;
+
+ if (!segments) {
+ segments = &default_ldt[0];
+ count = 5;
+ }
+
+ queue_set_ldt((unsigned long)segments, count);
+}
+
+#endif /* __ASSEMBLY__ */
+
+#endif /* __ARCH_DESC_H__ */
--- /dev/null
+/*
+ * fixmap.h: compile-time virtual memory allocation
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 1998 Ingo Molnar
+ *
+ * Support of BIGMEM added by Gerhard Wichert, Siemens AG, July 1999
+ */
+
+#ifndef _ASM_FIXMAP_H
+#define _ASM_FIXMAP_H
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <asm/apicdef.h>
+#include <asm/page.h>
+
+/*
+ * Here we define all the compile-time 'special' virtual
+ * addresses. The point is to have a constant address at
+ * compile time, but to set the physical address only
+ * in the boot process. We allocate these special addresses
+ * from the end of virtual memory (0xfffff000) backwards.
+ * Also this lets us do fail-safe vmalloc(), we
+ * can guarantee that these special addresses and
+ * vmalloc()-ed addresses never overlap.
+ *
+ * these 'compile-time allocated' memory buffers are
+ * fixed-size 4k pages. (or larger if used with an increment
+ * highger than 1) use fixmap_set(idx,phys) to associate
+ * physical memory with fixmap indices.
+ *
+ * TLB entries of such buffers will not be flushed across
+ * task switches.
+ */
+
+enum fixed_addresses {
+#ifdef CONFIG_HIGHMEM_XXX
+ FIX_KMAP_BEGIN, /* reserved pte's for temporary kernel mappings */
+ FIX_KMAP_END = FIX_KMAP_BEGIN+(KM_TYPE_NR*NR_CPUS)-1,
+#endif
+ FIX_BLKRING_BASE,
+ FIX_NETRING0_BASE,
+ FIX_NETRING1_BASE,
+ FIX_NETRING2_BASE,
+ FIX_NETRING3_BASE,
+ __end_of_permanent_fixed_addresses,
+ __end_of_fixed_addresses
+};
+
+extern void __set_fixmap (enum fixed_addresses idx,
+ unsigned long phys, pgprot_t flags);
+
+#define set_fixmap(idx, phys) \
+ __set_fixmap(idx, phys, PAGE_KERNEL)
+/*
+ * Some hardware wants to get fixmapped without caching.
+ */
+#define set_fixmap_nocache(idx, phys) \
+ __set_fixmap(idx, phys, PAGE_KERNEL_NOCACHE)
+/*
+ * used by vmalloc.c.
+ *
+ * Leave one empty page between vmalloc'ed areas and
+ * the start of the fixmap, and leave one page empty
+ * at the top of mem..
+ */
+#define FIXADDR_TOP (HYPERVISOR_VIRT_START - 2*PAGE_SIZE)
+#define __FIXADDR_SIZE (__end_of_fixed_addresses << PAGE_SHIFT)
+#define FIXADDR_START (FIXADDR_TOP - __FIXADDR_SIZE)
+
+#define __fix_to_virt(x) (FIXADDR_TOP - ((x) << PAGE_SHIFT))
+
+/*
+ * 'index to address' translation. If anyone tries to use the idx
+ * directly without tranlation, we catch the bug with a NULL-deference
+ * kernel oops. Illegal ranges of incoming indices are caught too.
+ */
+static inline unsigned long fix_to_virt(unsigned int idx)
+{
+ return __fix_to_virt(idx);
+}
+
+#endif
--- /dev/null
+#error "Highmem unsupported!"
+
--- /dev/null
+#ifndef _ASM_HW_IRQ_H
+#define _ASM_HW_IRQ_H
+
+/*
+ * linux/include/asm/hw_irq.h
+ *
+ * (C) 1992, 1993 Linus Torvalds, (C) 1997 Ingo Molnar
+ */
+
+#include <linux/config.h>
+#include <linux/smp.h>
+#include <asm/atomic.h>
+#include <asm/irq.h>
+
+#define SYSCALL_VECTOR 0x80
+
+extern int irq_vector[NR_IRQS];
+
+extern atomic_t irq_err_count;
+extern atomic_t irq_mis_count;
+
+extern char _stext, _etext;
+
+extern unsigned long prof_cpu_mask;
+extern unsigned int * prof_buffer;
+extern unsigned long prof_len;
+extern unsigned long prof_shift;
+
+/*
+ * x86 profiling function, SMP safe. We might want to do this in
+ * assembly totally?
+ */
+static inline void x86_do_profile (unsigned long eip)
+{
+ if (!prof_buffer)
+ return;
+
+ /*
+ * Only measure the CPUs specified by /proc/irq/prof_cpu_mask.
+ * (default is all CPUs.)
+ */
+ if (!((1<<smp_processor_id()) & prof_cpu_mask))
+ return;
+
+ eip -= (unsigned long) &_stext;
+ eip >>= prof_shift;
+ /*
+ * Don't ignore out-of-bounds EIP values silently,
+ * put them into the last histogram slot, so if
+ * present, they will show up as a sharp peak.
+ */
+ if (eip > prof_len-1)
+ eip = prof_len-1;
+ atomic_inc((atomic_t *)&prof_buffer[eip]);
+}
+
+static inline void hw_resend_irq(struct hw_interrupt_type *h,
+ unsigned int i)
+{}
+
+#endif /* _ASM_HW_IRQ_H */
--- /dev/null
+/******************************************************************************
+ * hypervisor.h
+ *
+ * Linux-specific hypervisor handling.
+ *
+ * Copyright (c) 2002, K A Fraser
+ */
+
+#ifndef __HYPERVISOR_H__
+#define __HYPERVISOR_H__
+
+#include <asm/hypervisor-ifs/hypervisor-if.h>
+#include <asm/ptrace.h>
+//#include <asm/page.h>
+
+/* arch/xeno/kernel/setup.c */
+union start_info_union
+{
+ start_info_t start_info;
+ char padding[512];
+};
+extern union start_info_union start_info_union;
+#define start_info (start_info_union.start_info)
+
+/* arch/xeno/kernel/hypervisor.c */
+void do_hypervisor_callback(struct pt_regs *regs);
+
+
+/* arch/xeno/mm/hypervisor.c */
+/*
+ * NB. ptr values should be PHYSICAL, not MACHINE. 'vals' should be already
+ * be MACHINE addresses.
+ */
+
+extern unsigned int pt_update_queue_idx;
+
+void queue_l1_entry_update(unsigned long ptr, unsigned long val);
+void queue_l2_entry_update(unsigned long ptr, unsigned long val);
+void queue_pt_switch(unsigned long ptr);
+void queue_tlb_flush(void);
+void queue_invlpg(unsigned long ptr);
+void queue_pgd_pin(unsigned long ptr);
+void queue_pgd_unpin(unsigned long ptr);
+void queue_pte_pin(unsigned long ptr);
+void queue_pte_unpin(unsigned long ptr);
+void queue_set_ldt(unsigned long ptr, unsigned long bytes);
+#define PT_UPDATE_DEBUG 0
+
+#if PT_UPDATE_DEBUG > 0
+typedef struct {
+ unsigned long ptr, val, pteval;
+ void *ptep;
+ int line; char *file;
+} page_update_debug_t;
+extern page_update_debug_t update_debug_queue[];
+#define queue_l1_entry_update(_p,_v) ({ \
+ update_debug_queue[pt_update_queue_idx].ptr = (_p); \
+ update_debug_queue[pt_update_queue_idx].val = (_v); \
+ update_debug_queue[pt_update_queue_idx].line = __LINE__; \
+ update_debug_queue[pt_update_queue_idx].file = __FILE__; \
+ queue_l1_entry_update((_p),(_v)); \
+})
+#define queue_l2_entry_update(_p,_v) ({ \
+ update_debug_queue[pt_update_queue_idx].ptr = (_p); \
+ update_debug_queue[pt_update_queue_idx].val = (_v); \
+ update_debug_queue[pt_update_queue_idx].line = __LINE__; \
+ update_debug_queue[pt_update_queue_idx].file = __FILE__; \
+ queue_l2_entry_update((_p),(_v)); \
+})
+#endif
+
+#if PT_UPDATE_DEBUG > 1
+#undef queue_l1_entry_update
+#undef queue_l2_entry_update
+#define queue_l1_entry_update(_p,_v) ({ \
+ update_debug_queue[pt_update_queue_idx].ptr = (_p); \
+ update_debug_queue[pt_update_queue_idx].val = (_v); \
+ update_debug_queue[pt_update_queue_idx].line = __LINE__; \
+ update_debug_queue[pt_update_queue_idx].file = __FILE__; \
+ printk("L1 %s %d: %08lx (%08lx -> %08lx)\n", __FILE__, __LINE__, \
+ phys_to_machine(_p), *(unsigned long *)__va(_p), \
+ (unsigned long)(_v)); \
+ queue_l1_entry_update((_p),(_v)); \
+})
+#define queue_l2_entry_update(_p,_v) ({ \
+ update_debug_queue[pt_update_queue_idx].ptr = (_p); \
+ update_debug_queue[pt_update_queue_idx].val = (_v); \
+ update_debug_queue[pt_update_queue_idx].line = __LINE__; \
+ update_debug_queue[pt_update_queue_idx].file = __FILE__; \
+ printk("L2 %s %d: %08lx (%08lx -> %08lx)\n", __FILE__, __LINE__, \
+ phys_to_machine(_p), *(unsigned long *)__va(_p), \
+ (unsigned long)(_v)); \
+ queue_l2_entry_update((_p),(_v)); \
+})
+#define queue_pt_switch(_p) ({ \
+ printk("PTSWITCH %s %d: %08lx\n", __FILE__, __LINE__, (_p)); \
+ queue_pt_switch(_p); \
+})
+#define queue_tlb_flush() ({ \
+ printk("TLB FLUSH %s %d\n", __FILE__, __LINE__); \
+ queue_tlb_flush(); \
+})
+#define queue_invlpg(_p) ({ \
+ printk("INVLPG %s %d: %08lx\n", __FILE__, __LINE__, (_p)); \
+ queue_invlpg(_p); \
+})
+#define queue_pgd_pin(_p) ({ \
+ printk("PGD PIN %s %d: %08lx\n", __FILE__, __LINE__, (_p)); \
+ queue_pgd_pin(_p); \
+})
+#define queue_pgd_unpin(_p) ({ \
+ printk("PGD UNPIN %s %d: %08lx\n", __FILE__, __LINE__, (_p)); \
+ queue_pgd_unpin(_p); \
+})
+#define queue_pte_pin(_p) ({ \
+ printk("PTE PIN %s %d: %08lx\n", __FILE__, __LINE__, (_p)); \
+ queue_pte_pin(_p); \
+})
+#define queue_pte_unpin(_p) ({ \
+ printk("PTE UNPIN %s %d: %08lx\n", __FILE__, __LINE__, (_p)); \
+ queue_pte_unpin(_p); \
+})
+#define queue_set_ldt(_p,_l) ({ \
+ printk("SETL LDT %s %d: %08lx %d\n", __FILE__, __LINE__, (_p), (_l)); \
+ queue_set_ldt((_p), (_l)); \
+})
+#endif
+
+void _flush_page_update_queue(void);
+static inline int flush_page_update_queue(void)
+{
+ unsigned int idx = pt_update_queue_idx;
+ if ( idx != 0 ) _flush_page_update_queue();
+ return idx;
+}
+#define XENO_flush_page_update_queue() (_flush_page_update_queue())
+void MULTICALL_flush_page_update_queue(void);
+
+
+/*
+ * Assembler stubs for hyper-calls.
+ */
+
+static inline int HYPERVISOR_set_trap_table(trap_info_t *table)
+{
+ int ret;
+ __asm__ __volatile__ (
+ TRAP_INSTR
+ : "=a" (ret) : "0" (__HYPERVISOR_set_trap_table),
+ "b" (table) );
+
+ return ret;
+}
+
+
+static inline int HYPERVISOR_pt_update(page_update_request_t *req, int count)
+{
+ int ret;
+ __asm__ __volatile__ (
+ TRAP_INSTR
+ : "=a" (ret) : "0" (__HYPERVISOR_pt_update),
+ "b" (req), "c" (count) );
+
+ return ret;
+}
+
+
+static inline int HYPERVISOR_console_write(const char *str, int count)
+{
+ int ret;
+ __asm__ __volatile__ (
+ TRAP_INSTR
+ : "=a" (ret) : "0" (__HYPERVISOR_console_write),
+ "b" (str), "c" (count) );
+
+
+ return ret;
+}
+
+static inline int HYPERVISOR_set_gdt(unsigned long *frame_list, int entries)
+{
+ int ret;
+ __asm__ __volatile__ (
+ TRAP_INSTR
+ : "=a" (ret) : "0" (__HYPERVISOR_set_gdt),
+ "b" (frame_list), "c" (entries) );
+
+
+ return ret;
+}
+
+static inline int HYPERVISOR_stack_switch(unsigned long ss, unsigned long esp)
+{
+ int ret;
+ __asm__ __volatile__ (
+ TRAP_INSTR
+ : "=a" (ret) : "0" (__HYPERVISOR_stack_switch),
+ "b" (ss), "c" (esp) : "memory" );
+
+ return ret;
+}
+
+static inline int HYPERVISOR_set_callbacks(
+ unsigned long event_selector, unsigned long event_address,
+ unsigned long failsafe_selector, unsigned long failsafe_address)
+{
+ int ret;
+ __asm__ __volatile__ (
+ TRAP_INSTR
+ : "=a" (ret) : "0" (__HYPERVISOR_set_callbacks),
+ "b" (event_selector), "c" (event_address),
+ "d" (failsafe_selector), "S" (failsafe_address) : "memory" );
+
+ return ret;
+}
+
+static inline int HYPERVISOR_net_update(void)
+{
+ int ret;
+ __asm__ __volatile__ (
+ TRAP_INSTR
+ : "=a" (ret) : "0" (__HYPERVISOR_net_update) );
+
+ return ret;
+}
+
+static inline int HYPERVISOR_fpu_taskswitch(void)
+{
+ int ret;
+ __asm__ __volatile__ (
+ TRAP_INSTR
+ : "=a" (ret) : "0" (__HYPERVISOR_fpu_taskswitch) );
+
+ return ret;
+}
+
+static inline int HYPERVISOR_yield(void)
+{
+ int ret;
+ __asm__ __volatile__ (
+ TRAP_INSTR
+ : "=a" (ret) : "0" (__HYPERVISOR_yield) );
+
+ return ret;
+}
+
+static inline int HYPERVISOR_exit(void)
+{
+ int ret;
+ __asm__ __volatile__ (
+ TRAP_INSTR
+ : "=a" (ret) : "0" (__HYPERVISOR_exit) );
+
+ return ret;
+}
+
+static inline int HYPERVISOR_dom0_op(void *dom0_op)
+{
+ int ret;
+ __asm__ __volatile__ (
+ TRAP_INSTR
+ : "=a" (ret) : "0" (__HYPERVISOR_dom0_op),
+ "b" (dom0_op) : "memory" );
+
+ return ret;
+}
+
+static inline int HYPERVISOR_network_op(void *network_op)
+{
+ int ret;
+ __asm__ __volatile__ (
+ TRAP_INSTR
+ : "=a" (ret) : "0" (__HYPERVISOR_network_op),
+ "b" (network_op) );
+
+ return ret;
+}
+
+static inline int HYPERVISOR_block_io_op(void)
+{
+ int ret;
+ __asm__ __volatile__ (
+ TRAP_INSTR
+ : "=a" (ret) : "0" (__HYPERVISOR_block_io_op) );
+
+ return ret;
+}
+
+static inline int HYPERVISOR_set_debugreg(int reg, unsigned long value)
+{
+ int ret;
+ __asm__ __volatile__ (
+ TRAP_INSTR
+ : "=a" (ret) : "0" (__HYPERVISOR_set_debugreg),
+ "b" (reg), "c" (value) );
+
+ return ret;
+}
+
+static inline unsigned long HYPERVISOR_get_debugreg(int reg)
+{
+ unsigned long ret;
+ __asm__ __volatile__ (
+ TRAP_INSTR
+ : "=a" (ret) : "0" (__HYPERVISOR_get_debugreg),
+ "b" (reg) );
+
+ return ret;
+}
+
+static inline int HYPERVISOR_update_descriptor(
+ unsigned long pa, unsigned long word1, unsigned long word2)
+{
+ int ret;
+ __asm__ __volatile__ (
+ TRAP_INSTR
+ : "=a" (ret) : "0" (__HYPERVISOR_update_descriptor),
+ "b" (pa), "c" (word1), "d" (word2) );
+
+ return ret;
+}
+
+static inline int HYPERVISOR_set_fast_trap(int idx)
+{
+ int ret;
+ __asm__ __volatile__ (
+ TRAP_INSTR
+ : "=a" (ret) : "0" (__HYPERVISOR_set_fast_trap),
+ "b" (idx) );
+
+ return ret;
+}
+
+static inline int HYPERVISOR_dom_mem_op(void *dom_mem_op)
+{
+ int ret;
+ __asm__ __volatile__ (
+ TRAP_INSTR
+ : "=a" (ret) : "0" (__HYPERVISOR_dom_mem_op),
+ "b" (dom_mem_op) : "memory" );
+
+ return ret;
+}
+
+static inline int HYPERVISOR_multicall(void *call_list, int nr_calls)
+{
+ int ret;
+ __asm__ __volatile__ (
+ TRAP_INSTR
+ : "=a" (ret) : "0" (__HYPERVISOR_multicall),
+ "b" (call_list), "c" (nr_calls) : "memory" );
+
+ return ret;
+}
+
+static inline long HYPERVISOR_kbd_op(unsigned char op, unsigned char val)
+{
+ int ret;
+ __asm__ __volatile__ (
+ TRAP_INSTR
+ : "=a" (ret) : "0" (__HYPERVISOR_kbd_op),
+ "b" (op), "c" (val) );
+
+ return ret;
+}
+
+static inline long HYPERVISOR_set_priv_levels(unsigned int new_io_pl,
+ unsigned int new_hypercall_pl)
+{
+ int ret;
+ __asm__ __volatile__ (
+ TRAP_INSTR
+ : "=a" (ret) : "0" (__HYPERVISOR_set_priv_levels),
+ "b" (new_io_pl), "c" (new_hypercall_pl) );
+
+ return ret;
+}
+
+#endif /* __HYPERVISOR_H__ */
--- /dev/null
+#ifndef _ASM_IO_H
+#define _ASM_IO_H
+
+#include <linux/config.h>
+#include <asm/hypervisor.h>
+/*
+ * This file contains the definitions for the x86 IO instructions
+ * inb/inw/inl/outb/outw/outl and the "string versions" of the same
+ * (insb/insw/insl/outsb/outsw/outsl). You can also use "pausing"
+ * versions of the single-IO instructions (inb_p/inw_p/..).
+ *
+ * This file is not meant to be obfuscating: it's just complicated
+ * to (a) handle it all in a way that makes gcc able to optimize it
+ * as well as possible and (b) trying to avoid writing the same thing
+ * over and over again with slight variations and possibly making a
+ * mistake somewhere.
+ */
+
+/*
+ * Thanks to James van Artsdalen for a better timing-fix than
+ * the two short jumps: using outb's to a nonexistent port seems
+ * to guarantee better timings even on fast machines.
+ *
+ * On the other hand, I'd like to be sure of a non-existent port:
+ * I feel a bit unsafe about using 0x80 (should be safe, though)
+ *
+ * Linus
+ */
+
+ /*
+ * Bit simplified and optimized by Jan Hubicka
+ * Support of BIGMEM added by Gerhard Wichert, Siemens AG, July 1999.
+ *
+ * isa_memset_io, isa_memcpy_fromio, isa_memcpy_toio added,
+ * isa_read[wl] and isa_write[wl] fixed
+ * - Arnaldo Carvalho de Melo <acme@conectiva.com.br>
+ */
+
+#define IO_SPACE_LIMIT 0xffff
+
+#define XQUAD_PORTIO_BASE 0xfe400000
+#define XQUAD_PORTIO_QUAD 0x40000 /* 256k per quad. */
+#define XQUAD_PORTIO_LEN 0x80000 /* Only remapping first 2 quads */
+
+#ifdef __KERNEL__
+
+#include <linux/vmalloc.h>
+
+/*
+ * Temporary debugging check to catch old code using
+ * unmapped ISA addresses. Will be removed in 2.4.
+ */
+#if CONFIG_DEBUG_IOVIRT
+ extern void *__io_virt_debug(unsigned long x, const char *file, int line);
+ extern unsigned long __io_phys_debug(unsigned long x, const char *file, int line);
+ #define __io_virt(x) __io_virt_debug((unsigned long)(x), __FILE__, __LINE__)
+//#define __io_phys(x) __io_phys_debug((unsigned long)(x), __FILE__, __LINE__)
+#else
+ #define __io_virt(x) ((void *)(x))
+//#define __io_phys(x) __pa(x)
+#endif
+
+/**
+ * virt_to_phys - map virtual addresses to physical
+ * @address: address to remap
+ *
+ * The returned physical address is the physical (CPU) mapping for
+ * the memory address given. It is only valid to use this function on
+ * addresses directly mapped or allocated via kmalloc.
+ *
+ * This function does not give bus mappings for DMA transfers. In
+ * almost all conceivable cases a device driver should not be using
+ * this function
+ */
+
+static inline unsigned long virt_to_phys(volatile void * address)
+{
+ return __pa(address);
+}
+
+/**
+ * phys_to_virt - map physical address to virtual
+ * @address: address to remap
+ *
+ * The returned virtual address is a current CPU mapping for
+ * the memory address given. It is only valid to use this function on
+ * addresses that have a kernel mapping
+ *
+ * This function does not handle bus mappings for DMA transfers. In
+ * almost all conceivable cases a device driver should not be using
+ * this function
+ */
+
+static inline void * phys_to_virt(unsigned long address)
+{
+ return __va(address);
+}
+
+/*
+ * Change "struct page" to physical address.
+ */
+#ifdef CONFIG_HIGHMEM64G
+#define page_to_phys(page) ((u64)(page - mem_map) << PAGE_SHIFT)
+#else
+#define page_to_phys(page) ((page - mem_map) << PAGE_SHIFT)
+#endif
+
+/*
+ * IO bus memory addresses are also 1:1 with the physical address
+ */
+#define virt_to_bus virt_to_phys
+#define bus_to_virt phys_to_virt
+#define page_to_bus page_to_phys
+
+/*
+ * readX/writeX() are used to access memory mapped devices. On some
+ * architectures the memory mapped IO stuff needs to be accessed
+ * differently. On the x86 architecture, we just read/write the
+ * memory location directly.
+ */
+
+#define readb(addr) (*(volatile unsigned char *) __io_virt(addr))
+#define readw(addr) (*(volatile unsigned short *) __io_virt(addr))
+#define readl(addr) (*(volatile unsigned int *) __io_virt(addr))
+#define __raw_readb readb
+#define __raw_readw readw
+#define __raw_readl readl
+
+#define writeb(b,addr) (*(volatile unsigned char *) __io_virt(addr) = (b))
+#define writew(b,addr) (*(volatile unsigned short *) __io_virt(addr) = (b))
+#define writel(b,addr) (*(volatile unsigned int *) __io_virt(addr) = (b))
+#define __raw_writeb writeb
+#define __raw_writew writew
+#define __raw_writel writel
+
+#define memset_io(a,b,c) __memset(__io_virt(a),(b),(c))
+#define memcpy_fromio(a,b,c) __memcpy((a),__io_virt(b),(c))
+#define memcpy_toio(a,b,c) __memcpy(__io_virt(a),(b),(c))
+
+/*
+ * ISA space is 'always mapped' on a typical x86 system, no need to
+ * explicitly ioremap() it. The fact that the ISA IO space is mapped
+ * to PAGE_OFFSET is pure coincidence - it does not mean ISA values
+ * are physical addresses. The following constant pointer can be
+ * used as the IO-area pointer (it can be iounmapped as well, so the
+ * analogy with PCI is quite large):
+ */
+#define __ISA_IO_base ((char *)(PAGE_OFFSET))
+
+#define isa_readb(a) readb(__ISA_IO_base + (a))
+#define isa_readw(a) readw(__ISA_IO_base + (a))
+#define isa_readl(a) readl(__ISA_IO_base + (a))
+#define isa_writeb(b,a) writeb(b,__ISA_IO_base + (a))
+#define isa_writew(w,a) writew(w,__ISA_IO_base + (a))
+#define isa_writel(l,a) writel(l,__ISA_IO_base + (a))
+#define isa_memset_io(a,b,c) memset_io(__ISA_IO_base + (a),(b),(c))
+#define isa_memcpy_fromio(a,b,c) memcpy_fromio((a),__ISA_IO_base + (b),(c))
+#define isa_memcpy_toio(a,b,c) memcpy_toio(__ISA_IO_base + (a),(b),(c))
+
+
+/*
+ * Again, i386 does not require mem IO specific function.
+ */
+
+#define eth_io_copy_and_sum(a,b,c,d) eth_copy_and_sum((a),__io_virt(b),(c),(d))
+#define isa_eth_io_copy_and_sum(a,b,c,d) eth_copy_and_sum((a),__io_virt(__ISA_IO_base + (b)),(c),(d))
+
+/**
+ * check_signature - find BIOS signatures
+ * @io_addr: mmio address to check
+ * @signature: signature block
+ * @length: length of signature
+ *
+ * Perform a signature comparison with the mmio address io_addr. This
+ * address should have been obtained by ioremap.
+ * Returns 1 on a match.
+ */
+
+static inline int check_signature(unsigned long io_addr,
+ const unsigned char *signature, int length)
+{
+ int retval = 0;
+ do {
+ if (readb(io_addr) != *signature)
+ goto out;
+ io_addr++;
+ signature++;
+ length--;
+ } while (length);
+ retval = 1;
+out:
+ return retval;
+}
+
+/**
+ * isa_check_signature - find BIOS signatures
+ * @io_addr: mmio address to check
+ * @signature: signature block
+ * @length: length of signature
+ *
+ * Perform a signature comparison with the ISA mmio address io_addr.
+ * Returns 1 on a match.
+ *
+ * This function is deprecated. New drivers should use ioremap and
+ * check_signature.
+ */
+
+
+static inline int isa_check_signature(unsigned long io_addr,
+ const unsigned char *signature, int length)
+{
+ int retval = 0;
+ do {
+ if (isa_readb(io_addr) != *signature)
+ goto out;
+ io_addr++;
+ signature++;
+ length--;
+ } while (length);
+ retval = 1;
+out:
+ return retval;
+}
+
+/*
+ * Cache management
+ *
+ * This needed for two cases
+ * 1. Out of order aware processors
+ * 2. Accidentally out of order processors (PPro errata #51)
+ */
+
+#if defined(CONFIG_X86_OOSTORE) || defined(CONFIG_X86_PPRO_FENCE)
+
+static inline void flush_write_buffers(void)
+{
+ __asm__ __volatile__ ("lock; addl $0,0(%%esp)": : :"memory");
+}
+
+#define dma_cache_inv(_start,_size) flush_write_buffers()
+#define dma_cache_wback(_start,_size) flush_write_buffers()
+#define dma_cache_wback_inv(_start,_size) flush_write_buffers()
+
+#else
+
+/* Nothing to do */
+
+#define dma_cache_inv(_start,_size) do { } while (0)
+#define dma_cache_wback(_start,_size) do { } while (0)
+#define dma_cache_wback_inv(_start,_size) do { } while (0)
+#define flush_write_buffers()
+
+#endif
+
+#endif /* __KERNEL__ */
+
+#ifdef SLOW_IO_BY_JUMPING
+#define __SLOW_DOWN_IO "\njmp 1f\n1:\tjmp 1f\n1:"
+#else
+#define __SLOW_DOWN_IO "\noutb %%al,$0x80"
+#endif
+
+#ifdef REALLY_SLOW_IO
+#define __FULL_SLOW_DOWN_IO __SLOW_DOWN_IO __SLOW_DOWN_IO __SLOW_DOWN_IO __SLOW_DOWN_IO
+#else
+#define __FULL_SLOW_DOWN_IO __SLOW_DOWN_IO
+#endif
+
+#ifdef CONFIG_MULTIQUAD
+extern void *xquad_portio; /* Where the IO area was mapped */
+#endif /* CONFIG_MULTIQUAD */
+
+/*
+ * Talk about misusing macros..
+ */
+#define __OUT1(s,x) \
+static inline void out##s(unsigned x value, unsigned short port) {
+
+#define __OUT2(s,s1,s2) \
+__asm__ __volatile__ ("out" #s " %" s1 "0,%" s2 "1"
+
+#if defined (CONFIG_MULTIQUAD) && !defined(STANDALONE)
+#define __OUTQ(s,ss,x) /* Do the equivalent of the portio op on quads */ \
+static inline void out##ss(unsigned x value, unsigned short port) { \
+ if (xquad_portio) \
+ write##s(value, (unsigned long) xquad_portio + port); \
+ else /* We're still in early boot, running on quad 0 */ \
+ out##ss##_local(value, port); \
+} \
+static inline void out##ss##_quad(unsigned x value, unsigned short port, int quad) { \
+ if (xquad_portio) \
+ write##s(value, (unsigned long) xquad_portio + (XQUAD_PORTIO_QUAD*quad)\
+ + port); \
+}
+
+#define __INQ(s,ss) /* Do the equivalent of the portio op on quads */ \
+static inline RETURN_TYPE in##ss(unsigned short port) { \
+ if (xquad_portio) \
+ return read##s((unsigned long) xquad_portio + port); \
+ else /* We're still in early boot, running on quad 0 */ \
+ return in##ss##_local(port); \
+} \
+static inline RETURN_TYPE in##ss##_quad(unsigned short port, int quad) { \
+ if (xquad_portio) \
+ return read##s((unsigned long) xquad_portio + (XQUAD_PORTIO_QUAD*quad)\
+ + port); \
+ else\
+ return 0;\
+}
+#endif /* CONFIG_MULTIQUAD && !STANDALONE */
+
+#if !defined(CONFIG_MULTIQUAD) || defined(STANDALONE)
+#define __OUT(s,s1,x) \
+__OUT1(s,x) __OUT2(s,s1,"w") : : "a" (value), "Nd" (port)); } \
+__OUT1(s##_p,x) __OUT2(s,s1,"w") __FULL_SLOW_DOWN_IO : : "a" (value), "Nd" (port));}
+#else
+/* Make the default portio routines operate on quad 0 */
+#define __OUT(s,s1,x) \
+__OUT1(s##_local,x) __OUT2(s,s1,"w") : : "a" (value), "Nd" (port)); } \
+__OUT1(s##_p_local,x) __OUT2(s,s1,"w") __FULL_SLOW_DOWN_IO : : "a" (value), "Nd" (port));} \
+__OUTQ(s,s,x) \
+__OUTQ(s,s##_p,x)
+#endif /* !CONFIG_MULTIQUAD || STANDALONE */
+
+#define __IN1(s) \
+static inline RETURN_TYPE in##s(unsigned short port) { RETURN_TYPE _v;
+
+#define __IN2(s,s1,s2) \
+__asm__ __volatile__ ("in" #s " %" s2 "1,%" s1 "0"
+
+#if !defined(CONFIG_MULTIQUAD) || defined(STANDALONE)
+#define __IN(s,s1,i...) \
+__IN1(s) __IN2(s,s1,"w") : "=a" (_v) : "Nd" (port) ,##i ); return _v; } \
+__IN1(s##_p) __IN2(s,s1,"w") __FULL_SLOW_DOWN_IO : "=a" (_v) : "Nd" (port) ,##i ); return _v; }
+#else
+/* Make the default portio routines operate on quad 0 */
+#define __IN(s,s1,i...) \
+__IN1(s##_local) __IN2(s,s1,"w") : "=a" (_v) : "Nd" (port) ,##i ); return _v; } \
+__IN1(s##_p_local) __IN2(s,s1,"w") __FULL_SLOW_DOWN_IO : "=a" (_v) : "Nd" (port) ,##i ); return _v; } \
+__INQ(s,s) \
+__INQ(s,s##_p)
+#endif /* !CONFIG_MULTIQUAD || STANDALONE */
+
+#define __INS(s) \
+static inline void ins##s(unsigned short port, void * addr, unsigned long count) \
+{ __asm__ __volatile__ ("rep ; ins" #s \
+: "=D" (addr), "=c" (count) : "d" (port),"0" (addr),"1" (count)); }
+
+#define __OUTS(s) \
+static inline void outs##s(unsigned short port, const void * addr, unsigned long count) \
+{ __asm__ __volatile__ ("rep ; outs" #s \
+: "=S" (addr), "=c" (count) : "d" (port),"0" (addr),"1" (count)); }
+
+#define RETURN_TYPE unsigned char
+__IN(b,"")
+#undef RETURN_TYPE
+#define RETURN_TYPE unsigned short
+__IN(w,"")
+#undef RETURN_TYPE
+#define RETURN_TYPE unsigned int
+__IN(l,"")
+#undef RETURN_TYPE
+
+__OUT(b,"b",char)
+__OUT(w,"w",short)
+__OUT(l,,int)
+
+__INS(b)
+__INS(w)
+__INS(l)
+
+__OUTS(b)
+__OUTS(w)
+__OUTS(l)
+
+#endif
--- /dev/null
+#ifndef _ASM_IRQ_H
+#define _ASM_IRQ_H
+
+/*
+ * linux/include/asm/irq.h
+ *
+ * (C) 1992, 1993 Linus Torvalds, (C) 1997 Ingo Molnar
+ *
+ * IRQ/IPI changes taken from work by Thomas Radke
+ * <tomsoft@informatik.tu-chemnitz.de>
+ */
+
+#include <linux/config.h>
+#include <asm/hypervisor.h>
+#include <asm/ptrace.h>
+
+#define NET_TX_IRQ _EVENT_NET_TX
+#define NET_RX_IRQ _EVENT_NET_RX
+#define NET2_TX_IRQ _EVENT_NET2_TX
+#define NET2_RX_IRQ _EVENT_NET2_RX
+#define TIMER_IRQ _EVENT_TIMER
+
+#define NR_IRQS (sizeof(HYPERVISOR_shared_info->events) * 8)
+
+#define irq_cannonicalize(_irq) (_irq)
+
+extern void disable_irq(unsigned int);
+extern void disable_irq_nosync(unsigned int);
+extern void enable_irq(unsigned int);
+
+#ifdef CONFIG_X86_LOCAL_APIC
+#define ARCH_HAS_NMI_WATCHDOG /* See include/linux/nmi.h */
+#endif
+
+#endif /* _ASM_IRQ_H */
--- /dev/null
+/* xenolinux/include/asm-xeno/keyboard.h */
+/* Portions copyright (c) 2003 James Scott, Intel Research Cambridge */
+/* Talks to hypervisor to get PS/2 keyboard and mouse events, and send keyboard and mouse commands */
+
+/* Based on:
+ * linux/include/asm-i386/keyboard.h
+ *
+ * Created 3 Nov 1996 by Geert Uytterhoeven
+ */
+
+#ifndef _XENO_KEYBOARD_H
+#define _XENO_KEYBOARD_H
+
+#ifdef __KERNEL__
+
+#include <linux/kernel.h>
+#include <linux/ioport.h>
+#include <linux/kd.h>
+#include <linux/pm.h>
+#include <asm/io.h>
+
+
+#define KEYBOARD_IRQ _EVENT_KBD
+#define AUX_IRQ _EVENT_KBD
+
+/* THIS SECTION RELATIVELY UNTOUCHED */
+
+extern int pckbd_setkeycode(unsigned int scancode, unsigned int keycode);
+extern int pckbd_getkeycode(unsigned int scancode);
+extern int pckbd_translate(unsigned char scancode, unsigned char *keycode,
+ char raw_mode);
+extern char pckbd_unexpected_up(unsigned char keycode);
+extern void pckbd_leds(unsigned char leds);
+extern void pckbd_init_hw(void);
+extern int pckbd_pm_resume(struct pm_dev *, pm_request_t, void *);
+
+extern pm_callback pm_kbd_request_override;
+extern unsigned char pckbd_sysrq_xlate[128];
+
+#define kbd_setkeycode pckbd_setkeycode
+#define kbd_getkeycode pckbd_getkeycode
+#define kbd_translate pckbd_translate
+#define kbd_unexpected_up pckbd_unexpected_up
+#define kbd_leds pckbd_leds
+#define kbd_init_hw pckbd_init_hw
+#define kbd_sysrq_xlate pckbd_sysrq_xlate
+
+#define SYSRQ_KEY 0x54
+
+
+/* THIS SECTION TALKS TO XEN TO DO PS2 SUPPORT */
+#include <asm/hypervisor-ifs/kbd.h>
+#include <asm/hypervisor-ifs/hypervisor-if.h>
+
+/* resource allocation */
+#define kbd_request_region() do { } while (0)
+#define kbd_request_irq(handler) request_irq(_EVENT_KBD, handler, 0, "PS/2 kbd", NULL)
+
+// could implement these with command to xen to filter mouse stuff...
+#define aux_request_irq(hand, dev_id) 0
+#define aux_free_irq(dev_id) do { } while(0)
+
+/* Some stoneage hardware needs delays after some operations. */
+#define kbd_pause() do { } while(0)
+
+
+static unsigned char kbd_current_scancode = 0;
+
+static unsigned char kbd_read_input(void)
+{
+ //printk("kbd_read_input: returning scancode 0x%2x\n", kbd_current_scancode);
+ return kbd_current_scancode;
+}
+
+static unsigned char kbd_read_status(void)
+{
+ long res;
+ res = HYPERVISOR_kbd_op(KBD_OP_READ,0);
+ if(res<0) {
+ //printk("kbd_read_status: error from hypervisor: %d", res);
+ kbd_current_scancode = 0;
+ return 0; // error with our request - wrong domain?
+ }
+ kbd_current_scancode = KBD_CODE_SCANCODE(res);
+ //printk("kbd_read_status: returning status 0x%2x\n", KBD_CODE_STATUS(res));
+ return KBD_CODE_STATUS(res);
+}
+
+
+#define kbd_write_output(val) HYPERVISOR_kbd_op(KBD_OP_WRITEOUTPUT, val);
+#define kbd_write_command(val) HYPERVISOR_kbd_op(KBD_OP_WRITECOMMAND, val);
+
+
+#endif /* __KERNEL__ */
+#endif /* _XENO_KEYBOARD_H */
--- /dev/null
+#ifndef __i386_MMU_H
+#define __i386_MMU_H
+
+#include <linux/list.h>
+
+/* describes dirrectly mapped vma nodes */
+typedef struct {
+ struct list_head list;
+ unsigned long vm_start;
+ unsigned long vm_end;
+} direct_mmap_node_t;
+
+/*
+ * The i386 doesn't have a mmu context, but
+ * we put the segment information here.
+ */
+typedef struct {
+ void *segments;
+ unsigned long cpuvalid;
+ struct list_head direct_list;
+} mm_context_t;
+
+#endif
--- /dev/null
+#ifndef __I386_MMU_CONTEXT_H
+#define __I386_MMU_CONTEXT_H
+
+#include <linux/config.h>
+#include <asm/desc.h>
+#include <asm/atomic.h>
+#include <asm/pgalloc.h>
+#include <asm/multicall.h>
+
+/*
+ * possibly do the LDT unload here?
+ */
+
+extern int init_new_context(struct task_struct *tsk, struct mm_struct *);
+extern void destroy_context(struct mm_struct *);
+
+//#define destroy_context(mm) do { } while(0)
+//#define init_new_context(tsk,mm) 0
+
+#ifdef CONFIG_SMP
+
+static inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk, unsigned cpu)
+{
+ if(cpu_tlbstate[cpu].state == TLBSTATE_OK)
+ cpu_tlbstate[cpu].state = TLBSTATE_LAZY;
+}
+#else
+static inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk, unsigned cpu)
+{
+}
+#endif
+
+extern pgd_t *cur_pgd;
+
+static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next, struct task_struct *tsk, unsigned cpu)
+{
+ if (prev != next) {
+ /* stop flush ipis for the previous mm */
+ clear_bit(cpu, &prev->cpu_vm_mask);
+ /*
+ * Re-load LDT if necessary
+ */
+ if (prev->context.segments != next->context.segments)
+ load_LDT(next);
+#ifdef CONFIG_SMP
+ cpu_tlbstate[cpu].state = TLBSTATE_OK;
+ cpu_tlbstate[cpu].active_mm = next;
+#endif
+ set_bit(cpu, &next->cpu_vm_mask);
+ set_bit(cpu, &next->context.cpuvalid);
+ /* Re-load page tables */
+ cur_pgd = next->pgd;
+ queue_pt_switch(__pa(cur_pgd));
+ }
+#ifdef CONFIG_SMP
+ else {
+ cpu_tlbstate[cpu].state = TLBSTATE_OK;
+ if(cpu_tlbstate[cpu].active_mm != next)
+ out_of_line_bug();
+ if(!test_and_set_bit(cpu, &next->cpu_vm_mask)) {
+ /* We were in lazy tlb mode and leave_mm disabled
+ * tlb flush IPI delivery. We must reload %cr3.
+ */
+ load_cr3(next->pgd);
+ }
+ if (!test_and_set_bit(cpu, &next->context.cpuvalid))
+ load_LDT(next);
+ }
+#endif
+}
+
+#define activate_mm(prev, next) \
+do { \
+ switch_mm((prev),(next),NULL,smp_processor_id()); \
+ flush_page_update_queue(); \
+} while ( 0 )
+
+#endif
--- /dev/null
+/******************************************************************************
+ * multicall.h
+ */
+
+#ifndef __MULTICALL_H__
+#define __MULTICALL_H__
+
+#include <asm/hypervisor.h>
+
+extern multicall_entry_t multicall_list[];
+extern int nr_multicall_ents;
+
+static inline void queue_multicall0(unsigned long op)
+{
+ int i = nr_multicall_ents;
+ multicall_list[i].op = op;
+ nr_multicall_ents = i+1;
+}
+
+static inline void queue_multicall1(unsigned long op, unsigned long arg1)
+{
+ int i = nr_multicall_ents;
+ multicall_list[i].op = op;
+ multicall_list[i].args[0] = arg1;
+ nr_multicall_ents = i+1;
+}
+
+static inline void queue_multicall2(
+ unsigned long op, unsigned long arg1, unsigned long arg2)
+{
+ int i = nr_multicall_ents;
+ multicall_list[i].op = op;
+ multicall_list[i].args[0] = arg1;
+ multicall_list[i].args[1] = arg2;
+ nr_multicall_ents = i+1;
+}
+
+static inline void execute_multicall_list(void)
+{
+ if ( unlikely(nr_multicall_ents == 0) ) return;
+ (void)HYPERVISOR_multicall(multicall_list, nr_multicall_ents);
+ nr_multicall_ents = 0;
+}
+
+#endif /* __MULTICALL_H__ */
--- /dev/null
+#ifndef _I386_PAGE_H
+#define _I386_PAGE_H
+
+/* PAGE_SHIFT determines the page size */
+#define PAGE_SHIFT 12
+#define PAGE_SIZE (1UL << PAGE_SHIFT)
+#define PAGE_MASK (~(PAGE_SIZE-1))
+
+#ifdef __KERNEL__
+#ifndef __ASSEMBLY__
+
+#include <linux/config.h>
+#include <asm/hypervisor.h>
+
+#ifdef CONFIG_X86_USE_3DNOW
+
+#include <asm/mmx.h>
+
+#define clear_page(page) mmx_clear_page((void *)(page))
+#define copy_page(to,from) mmx_copy_page(to,from)
+
+#else
+
+/*
+ * On older X86 processors its not a win to use MMX here it seems.
+ * Maybe the K6-III ?
+ */
+
+#define clear_page(page) memset((void *)(page), 0, PAGE_SIZE)
+#define copy_page(to,from) memcpy((void *)(to), (void *)(from), PAGE_SIZE)
+
+#endif
+
+#define clear_user_page(page, vaddr) clear_page(page)
+#define copy_user_page(to, from, vaddr) copy_page(to, from)
+
+/**** MACHINE <-> PHYSICAL CONVERSION MACROS ****/
+extern unsigned long *phys_to_machine_mapping;
+#define pfn_to_mfn(_pfn) (phys_to_machine_mapping[(_pfn)])
+#define mfn_to_pfn(_mfn) (machine_to_phys_mapping[(_mfn)])
+static inline unsigned long phys_to_machine(unsigned long phys)
+{
+ unsigned long machine = pfn_to_mfn(phys >> PAGE_SHIFT);
+ machine = (machine << PAGE_SHIFT) | (phys & ~PAGE_MASK);
+ return machine;
+}
+static inline unsigned long machine_to_phys(unsigned long machine)
+{
+ unsigned long phys = mfn_to_pfn(machine >> PAGE_SHIFT);
+ phys = (phys << PAGE_SHIFT) | (machine & ~PAGE_MASK);
+ return phys;
+}
+
+/*
+ * These are used to make use of C type-checking..
+ */
+#if CONFIG_X86_PAE
+typedef struct { unsigned long pte_low, pte_high; } pte_t;
+typedef struct { unsigned long long pmd; } pmd_t;
+typedef struct { unsigned long long pgd; } pgd_t;
+#define pte_val(x) ((x).pte_low | ((unsigned long long)(x).pte_high << 32))
+#else
+typedef struct { unsigned long pte_low; } pte_t;
+typedef struct { unsigned long pmd; } pmd_t;
+typedef struct { unsigned long pgd; } pgd_t;
+static inline unsigned long pte_val(pte_t x)
+{
+ unsigned long ret = x.pte_low;
+ if ( (ret & 1) ) ret = machine_to_phys(ret);
+ return ret;
+}
+#endif
+#define PTE_MASK PAGE_MASK
+
+typedef struct { unsigned long pgprot; } pgprot_t;
+
+static inline unsigned long pmd_val(pmd_t x)
+{
+ unsigned long ret = x.pmd;
+ if ( (ret & 1) ) ret = machine_to_phys(ret);
+ return ret;
+}
+#define pgd_val(x) ({ BUG(); (unsigned long)0; })
+#define pgprot_val(x) ((x).pgprot)
+
+static inline pte_t __pte(unsigned long x)
+{
+ if ( (x & 1) ) x = phys_to_machine(x);
+ return ((pte_t) { (x) });
+}
+static inline pmd_t __pmd(unsigned long x)
+{
+ if ( (x & 1) ) x = phys_to_machine(x);
+ return ((pmd_t) { (x) });
+}
+#define __pgd(x) ({ BUG(); (pgprot_t) { 0 }; })
+#define __pgprot(x) ((pgprot_t) { (x) } )
+
+#endif /* !__ASSEMBLY__ */
+
+/* to align the pointer to the (next) page boundary */
+#define PAGE_ALIGN(addr) (((addr)+PAGE_SIZE-1)&PAGE_MASK)
+
+/*
+ * This handles the memory map.. We could make this a config
+ * option, but too many people screw it up, and too few need
+ * it.
+ *
+ * A __PAGE_OFFSET of 0xC0000000 means that the kernel has
+ * a virtual address space of one gigabyte, which limits the
+ * amount of physical memory you can use to about 950MB.
+ *
+ * If you want more physical memory than this then see the CONFIG_HIGHMEM4G
+ * and CONFIG_HIGHMEM64G options in the kernel configuration.
+ */
+
+#define __PAGE_OFFSET (0xC0000000)
+
+#ifndef __ASSEMBLY__
+
+/*
+ * Tell the user there is some problem. Beep too, so we can
+ * see^H^H^Hhear bugs in early bootup as well!
+ * The offending file and line are encoded after the "officially
+ * undefined" opcode for parsing in the trap handler.
+ */
+
+#if 1 /* Set to zero for a slightly smaller kernel */
+#define BUG() \
+ __asm__ __volatile__( "ud2\n" \
+ "\t.word %c0\n" \
+ "\t.long %c1\n" \
+ : : "i" (__LINE__), "i" (__FILE__))
+#else
+#define BUG() __asm__ __volatile__("ud2\n")
+#endif
+
+#define PAGE_BUG(page) do { \
+ BUG(); \
+} while (0)
+
+/* Pure 2^n version of get_order */
+static __inline__ int get_order(unsigned long size)
+{
+ int order;
+
+ size = (size-1) >> (PAGE_SHIFT-1);
+ order = -1;
+ do {
+ size >>= 1;
+ order++;
+ } while (size);
+ return order;
+}
+
+#endif /* __ASSEMBLY__ */
+
+#define PAGE_OFFSET ((unsigned long)__PAGE_OFFSET)
+#define __pa(x) ((unsigned long)(x)-PAGE_OFFSET)
+#define __va(x) ((void *)((unsigned long)(x)+PAGE_OFFSET))
+#define virt_to_page(kaddr) (mem_map + (__pa(kaddr) >> PAGE_SHIFT))
+#define VALID_PAGE(page) ((page - mem_map) < max_mapnr)
+
+#define VM_DATA_DEFAULT_FLAGS (VM_READ | VM_WRITE | VM_EXEC | \
+ VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC)
+
+/* VIRT <-> MACHINE conversion */
+#define virt_to_machine(_a) (phys_to_machine(__pa(_a)))
+#define machine_to_virt(_m) (__va(machine_to_phys(_m)))
+
+#endif /* __KERNEL__ */
+
+#endif /* _I386_PAGE_H */
--- /dev/null
+#ifndef _I386_PGALLOC_H
+#define _I386_PGALLOC_H
+
+#include <linux/config.h>
+#include <asm/processor.h>
+#include <asm/fixmap.h>
+#include <asm/hypervisor.h>
+#include <linux/threads.h>
+
+/*
+ * Quick lists are aligned so that least significant bits of array pointer
+ * are all zero when list is empty, and all one when list is full.
+ */
+#define QUICKLIST_ENTRIES 256
+#define QUICKLIST_EMPTY(_l) !((unsigned long)(_l) & ((QUICKLIST_ENTRIES*4)-1))
+#define QUICKLIST_FULL(_l) QUICKLIST_EMPTY((_l)+1)
+#define pgd_quicklist (current_cpu_data.pgd_quick)
+#define pmd_quicklist (current_cpu_data.pmd_quick)
+#define pte_quicklist (current_cpu_data.pte_quick)
+#define pgtable_cache_size (current_cpu_data.pgtable_cache_sz)
+
+#define pmd_populate(mm, pmd, pte) \
+ do { \
+ set_pmd(pmd, __pmd(_PAGE_TABLE + __pa(pte))); \
+ XENO_flush_page_update_queue(); \
+ } while ( 0 )
+
+/*
+ * Allocate and free page tables.
+ */
+
+#if defined (CONFIG_X86_PAE)
+
+#error "no PAE support as yet"
+
+/*
+ * We can't include <linux/slab.h> here, thus these uglinesses.
+ */
+struct kmem_cache_s;
+
+extern struct kmem_cache_s *pae_pgd_cachep;
+extern void *kmem_cache_alloc(struct kmem_cache_s *, int);
+extern void kmem_cache_free(struct kmem_cache_s *, void *);
+
+
+static inline pgd_t *get_pgd_slow(void)
+{
+ int i;
+ pgd_t *pgd = kmem_cache_alloc(pae_pgd_cachep, GFP_KERNEL);
+
+ if (pgd) {
+ for (i = 0; i < USER_PTRS_PER_PGD; i++) {
+ unsigned long pmd = __get_free_page(GFP_KERNEL);
+ if (!pmd)
+ goto out_oom;
+ clear_page(pmd);
+ set_pgd(pgd + i, __pgd(1 + __pa(pmd)));
+ }
+ memcpy(pgd + USER_PTRS_PER_PGD,
+ swapper_pg_dir + USER_PTRS_PER_PGD,
+ (PTRS_PER_PGD - USER_PTRS_PER_PGD) * sizeof(pgd_t));
+ }
+ return pgd;
+out_oom:
+ for (i--; i >= 0; i--)
+ free_page((unsigned long)__va(pgd_val(pgd[i])-1));
+ kmem_cache_free(pae_pgd_cachep, pgd);
+ return NULL;
+}
+
+#else
+
+static inline pgd_t *get_pgd_slow(void)
+{
+ pgd_t *pgd = (pgd_t *)__get_free_page(GFP_KERNEL);
+
+ if (pgd) {
+ memset(pgd, 0, USER_PTRS_PER_PGD * sizeof(pgd_t));
+ memcpy(pgd + USER_PTRS_PER_PGD,
+ init_mm.pgd + USER_PTRS_PER_PGD,
+ (PTRS_PER_PGD - USER_PTRS_PER_PGD) * sizeof(pgd_t));
+ __make_page_readonly(pgd);
+ queue_pgd_pin(__pa(pgd));
+
+ }
+ return pgd;
+}
+
+#endif /* CONFIG_X86_PAE */
+
+static inline pgd_t *get_pgd_fast(void)
+{
+ unsigned long ret;
+
+ if ( !QUICKLIST_EMPTY(pgd_quicklist) ) {
+ ret = *(--pgd_quicklist);
+ pgtable_cache_size--;
+
+ } else
+ ret = (unsigned long)get_pgd_slow();
+ return (pgd_t *)ret;
+}
+
+static inline void free_pgd_slow(pgd_t *pgd)
+{
+#if defined(CONFIG_X86_PAE)
+#error
+ int i;
+
+ for (i = 0; i < USER_PTRS_PER_PGD; i++)
+ free_page((unsigned long)__va(pgd_val(pgd[i])-1));
+ kmem_cache_free(pae_pgd_cachep, pgd);
+#else
+ queue_pgd_unpin(__pa(pgd));
+ __make_page_writeable(pgd);
+ free_page((unsigned long)pgd);
+#endif
+}
+
+static inline void free_pgd_fast(pgd_t *pgd)
+{
+ if ( !QUICKLIST_FULL(pgd_quicklist) ) {
+ *(pgd_quicklist++) = (unsigned long)pgd;
+ pgtable_cache_size++;
+ } else
+ free_pgd_slow(pgd);
+}
+
+static inline pte_t *pte_alloc_one(struct mm_struct *mm, unsigned long address)
+{
+ pte_t *pte;
+
+ pte = (pte_t *) __get_free_page(GFP_KERNEL);
+ if (pte)
+ {
+ clear_page(pte);
+ __make_page_readonly(pte);
+ queue_pte_pin(__pa(pte));
+ }
+ return pte;
+
+}
+
+static inline pte_t *pte_alloc_one_fast(struct mm_struct *mm,
+ unsigned long address)
+{
+ unsigned long ret = 0;
+ if ( !QUICKLIST_EMPTY(pte_quicklist) ) {
+ ret = *(--pte_quicklist);
+ pgtable_cache_size--;
+ }
+ return (pte_t *)ret;
+}
+
+static __inline__ void pte_free_slow(pte_t *pte)
+{
+ queue_pte_unpin(__pa(pte));
+ __make_page_writeable(pte);
+ free_page((unsigned long)pte);
+}
+
+static inline void pte_free_fast(pte_t *pte)
+{
+ if ( !QUICKLIST_FULL(pte_quicklist) ) {
+ *(pte_quicklist++) = (unsigned long)pte;
+ pgtable_cache_size++;
+ } else
+ pte_free_slow(pte);
+}
+
+#define pte_free(pte) pte_free_fast(pte)
+#define pgd_free(pgd) free_pgd_fast(pgd)
+#define pgd_alloc(mm) get_pgd_fast()
+
+/*
+ * allocating and freeing a pmd is trivial: the 1-entry pmd is
+ * inside the pgd, so has no extra memory associated with it.
+ * (In the PAE case we free the pmds as part of the pgd.)
+ */
+
+#define pmd_alloc_one_fast(mm, addr) ({ BUG(); ((pmd_t *)1); })
+#define pmd_alloc_one(mm, addr) ({ BUG(); ((pmd_t *)2); })
+#define pmd_free_slow(x) do { } while (0)
+#define pmd_free_fast(x) do { } while (0)
+#define pmd_free(x) do { } while (0)
+#define pgd_populate(mm, pmd, pte) BUG()
+
+extern int do_check_pgt_cache(int, int);
+
+/*
+ * TLB flushing:
+ *
+ * - flush_tlb() flushes the current mm struct TLBs
+ * - flush_tlb_all() flushes all processes TLBs
+ * - flush_tlb_mm(mm) flushes the specified mm context TLB's
+ * - flush_tlb_page(vma, vmaddr) flushes one page
+ * - flush_tlb_range(mm, start, end) flushes a range of pages
+ * - flush_tlb_pgtables(mm, start, end) flushes a range of page tables
+ *
+ * ..but the i386 has somewhat limited tlb flushing capabilities,
+ * and page-granular flushes are available only on i486 and up.
+ */
+
+#ifndef CONFIG_SMP
+
+#define flush_tlb() __flush_tlb()
+#define flush_tlb_all() __flush_tlb_all()
+#define local_flush_tlb() __flush_tlb()
+
+static inline void flush_tlb_mm(struct mm_struct *mm)
+{
+ if (mm == current->active_mm) queue_tlb_flush();
+ XENO_flush_page_update_queue();
+}
+
+static inline void flush_tlb_page(struct vm_area_struct *vma,
+ unsigned long addr)
+{
+ if (vma->vm_mm == current->active_mm) queue_invlpg(addr);
+ XENO_flush_page_update_queue();
+}
+
+static inline void flush_tlb_range(struct mm_struct *mm,
+ unsigned long start, unsigned long end)
+{
+ if (mm == current->active_mm) queue_tlb_flush();
+ XENO_flush_page_update_queue();
+}
+
+#else
+#error no guestos SMP support yet...
+#include <asm/smp.h>
+
+#define local_flush_tlb() \
+ __flush_tlb()
+
+extern void flush_tlb_all(void);
+extern void flush_tlb_current_task(void);
+extern void flush_tlb_mm(struct mm_struct *);
+extern void flush_tlb_page(struct vm_area_struct *, unsigned long);
+
+#define flush_tlb() flush_tlb_current_task()
+
+static inline void flush_tlb_range(struct mm_struct * mm, unsigned long start, unsigned long end)
+{
+ flush_tlb_mm(mm);
+}
+
+#define TLBSTATE_OK 1
+#define TLBSTATE_LAZY 2
+
+struct tlb_state
+{
+ struct mm_struct *active_mm;
+ int state;
+};
+extern struct tlb_state cpu_tlbstate[NR_CPUS];
+
+#endif /* CONFIG_SMP */
+
+static inline void flush_tlb_pgtables(struct mm_struct *mm,
+ unsigned long start, unsigned long end)
+{
+ /* i386 does not keep any page table caches in TLB */
+ XENO_flush_page_update_queue();
+}
+
+#endif /* _I386_PGALLOC_H */
--- /dev/null
+#ifndef _I386_PGTABLE_2LEVEL_H
+#define _I386_PGTABLE_2LEVEL_H
+
+/*
+ * traditional i386 two-level paging structure:
+ */
+
+#define PGDIR_SHIFT 22
+#define PTRS_PER_PGD 1024
+
+/*
+ * the i386 is two-level, so we don't really have any
+ * PMD directory physically.
+ */
+#define PMD_SHIFT 22
+#define PTRS_PER_PMD 1
+
+#define PTRS_PER_PTE 1024
+
+#define pte_ERROR(e) \
+ printk("%s:%d: bad pte %08lx.\n", __FILE__, __LINE__, (e).pte_low)
+#define pmd_ERROR(e) \
+ printk("%s:%d: bad pmd %08lx.\n", __FILE__, __LINE__, pmd_val(e))
+#define pgd_ERROR(e) \
+ printk("%s:%d: bad pgd %08lx.\n", __FILE__, __LINE__, pgd_val(e))
+
+/*
+ * The "pgd_xxx()" functions here are trivial for a folded two-level
+ * setup: the pgd is never bad, and a pmd always exists (as it's folded
+ * into the pgd entry)
+ */
+static inline int pgd_none(pgd_t pgd) { return 0; }
+static inline int pgd_bad(pgd_t pgd) { return 0; }
+static inline int pgd_present(pgd_t pgd) { return 1; }
+#define pgd_clear(xp) do { } while (0)
+
+#define set_pte(pteptr, pteval) queue_l1_entry_update(__pa(pteptr), (pteval).pte_low)
+#define set_pte_atomic(pteptr, pteval) queue_l1_entry_update(__pa(pteptr), (pteval).pte_low)
+#define set_pmd(pmdptr, pmdval) queue_l2_entry_update(__pa(pmdptr), (pmdval).pmd)
+#define set_pgd(pgdptr, pgdval) ((void)0)
+
+#define pgd_page(pgd) \
+((unsigned long) __va(pgd_val(pgd) & PAGE_MASK))
+
+static inline pmd_t * pmd_offset(pgd_t * dir, unsigned long address)
+{
+ return (pmd_t *) dir;
+}
+
+/*
+ * A note on implementation of this atomic 'get-and-clear' operation.
+ * This is actually very simple because XenoLinux can only run on a single
+ * processor. Therefore, we cannot race other processors setting the 'accessed'
+ * or 'dirty' bits on a page-table entry.
+ * Even if pages are shared between domains, that is not a problem because
+ * each domain will have separate page tables, with their own versions of
+ * accessed & dirty state.
+ */
+static inline pte_t ptep_get_and_clear(pte_t *xp)
+{
+ pte_t pte = *xp;
+ queue_l1_entry_update(__pa(xp), 0);
+ return pte;
+}
+
+#define pte_same(a, b) ((a).pte_low == (b).pte_low)
+#define pte_page(x) (mem_map+((unsigned long)((pte_val(x) >> PAGE_SHIFT))))
+#define pte_none(x) (!(x).pte_low)
+#define __mk_pte(page_nr,pgprot) __pte(((page_nr) << PAGE_SHIFT) | pgprot_val(pgprot))
+
+#endif /* _I386_PGTABLE_2LEVEL_H */
--- /dev/null
+#ifndef _I386_PGTABLE_H
+#define _I386_PGTABLE_H
+
+#include <linux/config.h>
+
+#define HAVE_ARCH_UNMAPPED_AREA
+
+/*
+ * The Linux memory management assumes a three-level page table setup. On
+ * the i386, we use that, but "fold" the mid level into the top-level page
+ * table, so that we physically have the same two-level page table as the
+ * i386 mmu expects.
+ *
+ * This file contains the functions and defines necessary to modify and use
+ * the i386 page table tree.
+ */
+#ifndef __ASSEMBLY__
+#include <asm/processor.h>
+#include <asm/hypervisor.h>
+#include <linux/threads.h>
+#include <asm/fixmap.h>
+
+#ifndef _I386_BITOPS_H
+#include <asm/bitops.h>
+#endif
+
+#define swapper_pg_dir 0
+extern void paging_init(void);
+
+/* Caches aren't brain-dead on the intel. */
+#define flush_cache_all() do { } while (0)
+#define flush_cache_mm(mm) do { } while (0)
+#define flush_cache_range(mm, start, end) do { } while (0)
+#define flush_cache_page(vma, vmaddr) do { } while (0)
+#define flush_page_to_ram(page) do { } while (0)
+#define flush_dcache_page(page) do { } while (0)
+#define flush_icache_range(start, end) do { } while (0)
+#define flush_icache_page(vma,pg) do { } while (0)
+#define flush_icache_user_range(vma,pg,adr,len) do { } while (0)
+
+extern unsigned long pgkern_mask;
+
+#define __flush_tlb() ({ queue_tlb_flush(); XENO_flush_page_update_queue(); })
+#define __flush_tlb_global() __flush_tlb()
+#define __flush_tlb_all() __flush_tlb_global()
+#define __flush_tlb_one(addr) ({ queue_invlpg(addr); XENO_flush_page_update_queue(); })
+#define __flush_tlb_single(addr) ({ queue_invlpg(addr); XENO_flush_page_update_queue(); })
+
+/*
+ * ZERO_PAGE is a global shared page that is always zero: used
+ * for zero-mapped memory areas etc..
+ */
+extern unsigned long empty_zero_page[1024];
+#define ZERO_PAGE(vaddr) (virt_to_page(empty_zero_page))
+
+#endif /* !__ASSEMBLY__ */
+
+/*
+ * The Linux x86 paging architecture is 'compile-time dual-mode', it
+ * implements both the traditional 2-level x86 page tables and the
+ * newer 3-level PAE-mode page tables.
+ */
+#ifndef __ASSEMBLY__
+#if CONFIG_X86_PAE
+# include <asm/pgtable-3level.h>
+
+/*
+ * Need to initialise the X86 PAE caches
+ */
+extern void pgtable_cache_init(void);
+
+#else
+# include <asm/pgtable-2level.h>
+
+/*
+ * No page table caches to initialise
+ */
+#define pgtable_cache_init() do { } while (0)
+
+#endif
+#endif
+
+#define PMD_SIZE (1UL << PMD_SHIFT)
+#define PMD_MASK (~(PMD_SIZE-1))
+#define PGDIR_SIZE (1UL << PGDIR_SHIFT)
+#define PGDIR_MASK (~(PGDIR_SIZE-1))
+
+#define USER_PTRS_PER_PGD (TASK_SIZE/PGDIR_SIZE)
+#define FIRST_USER_PGD_NR 0
+
+#define USER_PGD_PTRS (PAGE_OFFSET >> PGDIR_SHIFT)
+#define KERNEL_PGD_PTRS (PTRS_PER_PGD-USER_PGD_PTRS)
+
+#define TWOLEVEL_PGDIR_SHIFT 22
+#define BOOT_USER_PGD_PTRS (__PAGE_OFFSET >> TWOLEVEL_PGDIR_SHIFT)
+#define BOOT_KERNEL_PGD_PTRS (1024-BOOT_USER_PGD_PTRS)
+
+
+#ifndef __ASSEMBLY__
+/* 4MB is just a nice "safety zone". Also, we align to a fresh pde. */
+#define VMALLOC_OFFSET (4*1024*1024)
+extern void * high_memory;
+#define VMALLOC_START (((unsigned long) high_memory + 2*VMALLOC_OFFSET-1) & \
+ ~(VMALLOC_OFFSET-1))
+#define VMALLOC_VMADDR(x) ((unsigned long)(x))
+#define VMALLOC_END (FIXADDR_START - 2*PAGE_SIZE)
+
+#define _PAGE_BIT_PRESENT 0
+#define _PAGE_BIT_RW 1
+#define _PAGE_BIT_USER 2
+#define _PAGE_BIT_PWT 3
+#define _PAGE_BIT_PCD 4
+#define _PAGE_BIT_ACCESSED 5
+#define _PAGE_BIT_DIRTY 6
+#define _PAGE_BIT_PSE 7 /* 4 MB (or 2MB) page, Pentium+, if present.. */
+#define _PAGE_BIT_GLOBAL 8 /* Global TLB entry PPro+ */
+
+#define _PAGE_PRESENT 0x001
+#define _PAGE_RW 0x002
+#define _PAGE_USER 0x004
+#define _PAGE_PWT 0x008
+#define _PAGE_PCD 0x010
+#define _PAGE_ACCESSED 0x020
+#define _PAGE_DIRTY 0x040
+#define _PAGE_PSE 0x080 /* 4 MB (or 2MB) page, Pentium+, if present.. */
+#define _PAGE_GLOBAL 0x100 /* Global TLB entry PPro+ */
+
+#define _PAGE_PROTNONE 0x080 /* If not present */
+
+#define _PAGE_TABLE (_PAGE_PRESENT | _PAGE_RW | _PAGE_USER | _PAGE_ACCESSED | _PAGE_DIRTY)
+#define _KERNPG_TABLE (_PAGE_PRESENT | _PAGE_RW | _PAGE_ACCESSED | _PAGE_DIRTY)
+#define _PAGE_CHG_MASK (PTE_MASK | _PAGE_ACCESSED | _PAGE_DIRTY)
+
+#define PAGE_NONE __pgprot(_PAGE_PROTNONE | _PAGE_ACCESSED)
+#define PAGE_SHARED __pgprot(_PAGE_PRESENT | _PAGE_RW | _PAGE_USER | _PAGE_ACCESSED)
+#define PAGE_COPY __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_ACCESSED)
+#define PAGE_READONLY __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_ACCESSED)
+
+#define __PAGE_KERNEL \
+ (_PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY | _PAGE_ACCESSED)
+#define __PAGE_KERNEL_NOCACHE \
+ (_PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY | _PAGE_PCD | _PAGE_ACCESSED)
+#define __PAGE_KERNEL_RO \
+ (_PAGE_PRESENT | _PAGE_DIRTY | _PAGE_ACCESSED)
+
+#if 0
+#define MAKE_GLOBAL(x) __pgprot((x) | _PAGE_GLOBAL)
+#else
+#define MAKE_GLOBAL(x) __pgprot(x)
+#endif
+
+#define PAGE_KERNEL MAKE_GLOBAL(__PAGE_KERNEL)
+#define PAGE_KERNEL_RO MAKE_GLOBAL(__PAGE_KERNEL_RO)
+#define PAGE_KERNEL_NOCACHE MAKE_GLOBAL(__PAGE_KERNEL_NOCACHE)
+
+/*
+ * The i386 can't do page protection for execute, and considers that
+ * the same are read. Also, write permissions imply read permissions.
+ * This is the closest we can get..
+ */
+#define __P000 PAGE_NONE
+#define __P001 PAGE_READONLY
+#define __P010 PAGE_COPY
+#define __P011 PAGE_COPY
+#define __P100 PAGE_READONLY
+#define __P101 PAGE_READONLY
+#define __P110 PAGE_COPY
+#define __P111 PAGE_COPY
+
+#define __S000 PAGE_NONE
+#define __S001 PAGE_READONLY
+#define __S010 PAGE_SHARED
+#define __S011 PAGE_SHARED
+#define __S100 PAGE_READONLY
+#define __S101 PAGE_READONLY
+#define __S110 PAGE_SHARED
+#define __S111 PAGE_SHARED
+
+#define pte_present(x) ((x).pte_low & (_PAGE_PRESENT | _PAGE_PROTNONE))
+#define pte_clear(xp) queue_l1_entry_update(__pa(xp), 0)
+
+#define pmd_none(x) (!(x).pmd)
+#define pmd_present(x) ((x).pmd & _PAGE_PRESENT)
+#define pmd_clear(xp) do { set_pmd(xp, __pmd(0)); } while (0)
+#define pmd_bad(x) (((x).pmd & (~PAGE_MASK & ~_PAGE_USER)) != _KERNPG_TABLE)
+
+
+#define pages_to_mb(x) ((x) >> (20-PAGE_SHIFT))
+
+/*
+ * The following only work if pte_present() is true.
+ * Undefined behaviour if not..
+ */
+static inline int pte_read(pte_t pte) { return (pte).pte_low & _PAGE_USER; }
+static inline int pte_exec(pte_t pte) { return (pte).pte_low & _PAGE_USER; }
+static inline int pte_dirty(pte_t pte) { return (pte).pte_low & _PAGE_DIRTY; }
+static inline int pte_young(pte_t pte) { return (pte).pte_low & _PAGE_ACCESSED; }
+static inline int pte_write(pte_t pte) { return (pte).pte_low & _PAGE_RW; }
+
+static inline pte_t pte_rdprotect(pte_t pte) { (pte).pte_low &= ~_PAGE_USER; return pte; }
+static inline pte_t pte_exprotect(pte_t pte) { (pte).pte_low &= ~_PAGE_USER; return pte; }
+static inline pte_t pte_mkclean(pte_t pte) { (pte).pte_low &= ~_PAGE_DIRTY; return pte; }
+static inline pte_t pte_mkold(pte_t pte) { (pte).pte_low &= ~_PAGE_ACCESSED; return pte; }
+static inline pte_t pte_wrprotect(pte_t pte) { (pte).pte_low &= ~_PAGE_RW; return pte; }
+static inline pte_t pte_mkread(pte_t pte) { (pte).pte_low |= _PAGE_USER; return pte; }
+static inline pte_t pte_mkexec(pte_t pte) { (pte).pte_low |= _PAGE_USER; return pte; }
+static inline pte_t pte_mkdirty(pte_t pte) { (pte).pte_low |= _PAGE_DIRTY; return pte; }
+static inline pte_t pte_mkyoung(pte_t pte) { (pte).pte_low |= _PAGE_ACCESSED; return pte; }
+static inline pte_t pte_mkwrite(pte_t pte) { (pte).pte_low |= _PAGE_RW; return pte; }
+
+static inline int ptep_test_and_clear_dirty(pte_t *ptep)
+{
+ unsigned long pteval = *(unsigned long *)ptep;
+ int ret = pteval & _PAGE_DIRTY;
+ if ( ret ) queue_l1_entry_update(__pa(ptep), pteval & ~_PAGE_DIRTY);
+ return ret;
+}
+static inline int ptep_test_and_clear_young(pte_t *ptep)
+{
+ unsigned long pteval = *(unsigned long *)ptep;
+ int ret = pteval & _PAGE_ACCESSED;
+ if ( ret ) queue_l1_entry_update(__pa(ptep), pteval & ~_PAGE_ACCESSED);
+ return ret;
+}
+static inline void ptep_set_wrprotect(pte_t *ptep)
+{
+ unsigned long pteval = *(unsigned long *)ptep;
+ if ( (pteval & _PAGE_RW) )
+ queue_l1_entry_update(__pa(ptep), pteval & ~_PAGE_RW);
+}
+static inline void ptep_mkdirty(pte_t *ptep)
+{
+ unsigned long pteval = *(unsigned long *)ptep;
+ if ( !(pteval & _PAGE_DIRTY) )
+ queue_l1_entry_update(__pa(ptep), pteval | _PAGE_DIRTY);
+}
+
+/*
+ * Conversion functions: convert a page and protection to a page entry,
+ * and a page entry and page directory to the page they refer to.
+ */
+
+#define mk_pte(page, pgprot) __mk_pte((page) - mem_map, (pgprot))
+
+/* This takes a physical page address that is used by the remapping functions */
+#define mk_pte_phys(physpage, pgprot) __mk_pte((physpage) >> PAGE_SHIFT, pgprot)
+
+static inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
+{
+ pte.pte_low &= _PAGE_CHG_MASK;
+ pte.pte_low |= pgprot_val(newprot);
+ return pte;
+}
+
+#define page_pte(page) page_pte_prot(page, __pgprot(0))
+
+#define pmd_page(pmd) \
+((unsigned long) __va(pmd_val(pmd) & PAGE_MASK))
+
+/* to find an entry in a page-table-directory. */
+#define pgd_index(address) ((address >> PGDIR_SHIFT) & (PTRS_PER_PGD-1))
+
+#define __pgd_offset(address) pgd_index(address)
+
+#define pgd_offset(mm, address) ((mm)->pgd+pgd_index(address))
+
+/* to find an entry in a kernel page-table-directory */
+#define pgd_offset_k(address) pgd_offset(&init_mm, address)
+
+#define __pmd_offset(address) \
+ (((address) >> PMD_SHIFT) & (PTRS_PER_PMD-1))
+
+/* Find an entry in the third-level page table.. */
+#define __pte_offset(address) \
+ ((address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1))
+#define pte_offset(dir, address) ((pte_t *) pmd_page(*(dir)) + \
+ __pte_offset(address))
+
+/*
+ * The i386 doesn't have any external MMU info: the kernel page
+ * tables contain all the necessary information.
+ */
+#define update_mmu_cache(vma,address,pte) do { } while (0)
+
+/* Encode and de-code a swap entry */
+#define SWP_TYPE(x) (((x).val >> 1) & 0x3f)
+#define SWP_OFFSET(x) ((x).val >> 8)
+#define SWP_ENTRY(type, offset) ((swp_entry_t) { ((type) << 1) | ((offset) << 8) })
+#define pte_to_swp_entry(pte) ((swp_entry_t) { (pte).pte_low })
+#define swp_entry_to_pte(x) ((pte_t) { (x).val })
+
+struct page;
+int change_page_attr(struct page *, int, pgprot_t prot);
+
+static inline void __make_page_readonly(void *va)
+{
+ pgd_t *pgd = pgd_offset_k((unsigned long)va);
+ pmd_t *pmd = pmd_offset(pgd, (unsigned long)va);
+ pte_t *pte = pte_offset(pmd, (unsigned long)va);
+ queue_l1_entry_update(__pa(pte), (*(unsigned long *)pte)&~_PAGE_RW);
+}
+
+static inline void __make_page_writeable(void *va)
+{
+ pgd_t *pgd = pgd_offset_k((unsigned long)va);
+ pmd_t *pmd = pmd_offset(pgd, (unsigned long)va);
+ pte_t *pte = pte_offset(pmd, (unsigned long)va);
+ queue_l1_entry_update(__pa(pte), (*(unsigned long *)pte)|_PAGE_RW);
+}
+
+static inline void make_page_readonly(void *va)
+{
+ pgd_t *pgd = pgd_offset_k((unsigned long)va);
+ pmd_t *pmd = pmd_offset(pgd, (unsigned long)va);
+ pte_t *pte = pte_offset(pmd, (unsigned long)va);
+ queue_l1_entry_update(__pa(pte), (*(unsigned long *)pte)&~_PAGE_RW);
+ if ( (unsigned long)va >= VMALLOC_START )
+ __make_page_readonly(machine_to_virt(
+ *(unsigned long *)pte&PAGE_MASK));
+}
+
+static inline void make_page_writeable(void *va)
+{
+ pgd_t *pgd = pgd_offset_k((unsigned long)va);
+ pmd_t *pmd = pmd_offset(pgd, (unsigned long)va);
+ pte_t *pte = pte_offset(pmd, (unsigned long)va);
+ queue_l1_entry_update(__pa(pte), (*(unsigned long *)pte)|_PAGE_RW);
+ if ( (unsigned long)va >= VMALLOC_START )
+ __make_page_writeable(machine_to_virt(
+ *(unsigned long *)pte&PAGE_MASK));
+}
+
+static inline void make_pages_readonly(void *va, unsigned int nr)
+{
+ while ( nr-- != 0 )
+ {
+ make_page_readonly(va);
+ va = (void *)((unsigned long)va + PAGE_SIZE);
+ }
+}
+
+static inline void make_pages_writeable(void *va, unsigned int nr)
+{
+ while ( nr-- != 0 )
+ {
+ make_page_writeable(va);
+ va = (void *)((unsigned long)va + PAGE_SIZE);
+ }
+}
+
+static inline unsigned long arbitrary_virt_to_phys(void *va)
+{
+ pgd_t *pgd = pgd_offset_k((unsigned long)va);
+ pmd_t *pmd = pmd_offset(pgd, (unsigned long)va);
+ pte_t *pte = pte_offset(pmd, (unsigned long)va);
+ unsigned long pa = (*(unsigned long *)pte) & PAGE_MASK;
+ return pa | ((unsigned long)va & (PAGE_SIZE-1));
+}
+
+#endif /* !__ASSEMBLY__ */
+
+/* Needs to be defined here and not in linux/mm.h, as it is arch dependent */
+#define PageSkip(page) (0)
+#define kern_addr_valid(addr) (1)
+
+#define io_remap_page_range remap_page_range
+
+#endif /* _I386_PGTABLE_H */
--- /dev/null
+/*
+ * include/asm-i386/processor.h
+ *
+ * Copyright (C) 1994 Linus Torvalds
+ */
+
+#ifndef __ASM_I386_PROCESSOR_H
+#define __ASM_I386_PROCESSOR_H
+
+#include <asm/math_emu.h>
+#include <asm/segment.h>
+#include <asm/page.h>
+#include <asm/types.h>
+#include <asm/sigcontext.h>
+#include <asm/cpufeature.h>
+#include <linux/cache.h>
+#include <linux/config.h>
+#include <linux/threads.h>
+
+/*
+ * Default implementation of macro that returns current
+ * instruction pointer ("program counter").
+ */
+#define current_text_addr() ({ void *pc; __asm__("movl $1f,%0\n1:":"=g" (pc)); pc; })
+
+/*
+ * CPU type and hardware bug flags. Kept separately for each CPU.
+ * Members of this structure are referenced in head.S, so think twice
+ * before touching them. [mj]
+ */
+
+struct cpuinfo_x86 {
+ __u8 x86; /* CPU family */
+ __u8 x86_vendor; /* CPU vendor */
+ __u8 x86_model;
+ __u8 x86_mask;
+ char wp_works_ok; /* It doesn't on 386's */
+ char hlt_works_ok; /* Problems on some 486Dx4's and old 386's */
+ char hard_math;
+ char rfu;
+ int cpuid_level; /* Maximum supported CPUID level, -1=no CPUID */
+ __u32 x86_capability[NCAPINTS];
+ char x86_vendor_id[16];
+ char x86_model_id[64];
+ int x86_cache_size; /* in KB - valid for CPUS which support this
+ call */
+ int fdiv_bug;
+ int f00f_bug;
+ int coma_bug;
+ unsigned long loops_per_jiffy;
+ unsigned long *pgd_quick;
+ unsigned long *pmd_quick;
+ unsigned long *pte_quick;
+ unsigned long pgtable_cache_sz;
+} __attribute__((__aligned__(SMP_CACHE_BYTES)));
+
+#define X86_VENDOR_INTEL 0
+#define X86_VENDOR_CYRIX 1
+#define X86_VENDOR_AMD 2
+#define X86_VENDOR_UMC 3
+#define X86_VENDOR_NEXGEN 4
+#define X86_VENDOR_CENTAUR 5
+#define X86_VENDOR_RISE 6
+#define X86_VENDOR_TRANSMETA 7
+#define X86_VENDOR_NSC 8
+#define X86_VENDOR_SIS 9
+#define X86_VENDOR_UNKNOWN 0xff
+
+/*
+ * capabilities of CPUs
+ */
+
+extern struct cpuinfo_x86 boot_cpu_data;
+extern struct tss_struct init_tss[NR_CPUS];
+
+#ifdef CONFIG_SMP
+extern struct cpuinfo_x86 cpu_data[];
+#define current_cpu_data cpu_data[smp_processor_id()]
+#else
+#define cpu_data (&boot_cpu_data)
+#define current_cpu_data boot_cpu_data
+#endif
+
+#define cpu_has_pge (test_bit(X86_FEATURE_PGE, boot_cpu_data.x86_capability))
+#define cpu_has_pse (test_bit(X86_FEATURE_PSE, boot_cpu_data.x86_capability))
+#define cpu_has_pae (test_bit(X86_FEATURE_PAE, boot_cpu_data.x86_capability))
+#define cpu_has_tsc (test_bit(X86_FEATURE_TSC, boot_cpu_data.x86_capability))
+#define cpu_has_de (test_bit(X86_FEATURE_DE, boot_cpu_data.x86_capability))
+#define cpu_has_vme (test_bit(X86_FEATURE_VME, boot_cpu_data.x86_capability))
+#define cpu_has_fxsr (test_bit(X86_FEATURE_FXSR, boot_cpu_data.x86_capability))
+#define cpu_has_xmm (test_bit(X86_FEATURE_XMM, boot_cpu_data.x86_capability))
+#define cpu_has_fpu (test_bit(X86_FEATURE_FPU, boot_cpu_data.x86_capability))
+#define cpu_has_apic (test_bit(X86_FEATURE_APIC, boot_cpu_data.x86_capability))
+
+extern char ignore_irq13;
+
+extern void identify_cpu(struct cpuinfo_x86 *);
+extern void print_cpu_info(struct cpuinfo_x86 *);
+
+/*
+ * EFLAGS bits
+ */
+#define X86_EFLAGS_CF 0x00000001 /* Carry Flag */
+#define X86_EFLAGS_PF 0x00000004 /* Parity Flag */
+#define X86_EFLAGS_AF 0x00000010 /* Auxillary carry Flag */
+#define X86_EFLAGS_ZF 0x00000040 /* Zero Flag */
+#define X86_EFLAGS_SF 0x00000080 /* Sign Flag */
+#define X86_EFLAGS_TF 0x00000100 /* Trap Flag */
+#define X86_EFLAGS_IF 0x00000200 /* Interrupt Flag */
+#define X86_EFLAGS_DF 0x00000400 /* Direction Flag */
+#define X86_EFLAGS_OF 0x00000800 /* Overflow Flag */
+#define X86_EFLAGS_IOPL 0x00003000 /* IOPL mask */
+#define X86_EFLAGS_NT 0x00004000 /* Nested Task */
+#define X86_EFLAGS_RF 0x00010000 /* Resume Flag */
+#define X86_EFLAGS_VM 0x00020000 /* Virtual Mode */
+#define X86_EFLAGS_AC 0x00040000 /* Alignment Check */
+#define X86_EFLAGS_VIF 0x00080000 /* Virtual Interrupt Flag */
+#define X86_EFLAGS_VIP 0x00100000 /* Virtual Interrupt Pending */
+#define X86_EFLAGS_ID 0x00200000 /* CPUID detection flag */
+
+/*
+ * Generic CPUID function
+ */
+static inline void cpuid(int op, int *eax, int *ebx, int *ecx, int *edx)
+{
+ __asm__("cpuid"
+ : "=a" (*eax),
+ "=b" (*ebx),
+ "=c" (*ecx),
+ "=d" (*edx)
+ : "0" (op));
+}
+
+/*
+ * CPUID functions returning a single datum
+ */
+static inline unsigned int cpuid_eax(unsigned int op)
+{
+ unsigned int eax;
+
+ __asm__("cpuid"
+ : "=a" (eax)
+ : "0" (op)
+ : "bx", "cx", "dx");
+ return eax;
+}
+static inline unsigned int cpuid_ebx(unsigned int op)
+{
+ unsigned int eax, ebx;
+
+ __asm__("cpuid"
+ : "=a" (eax), "=b" (ebx)
+ : "0" (op)
+ : "cx", "dx" );
+ return ebx;
+}
+static inline unsigned int cpuid_ecx(unsigned int op)
+{
+ unsigned int eax, ecx;
+
+ __asm__("cpuid"
+ : "=a" (eax), "=c" (ecx)
+ : "0" (op)
+ : "bx", "dx" );
+ return ecx;
+}
+static inline unsigned int cpuid_edx(unsigned int op)
+{
+ unsigned int eax, edx;
+
+ __asm__("cpuid"
+ : "=a" (eax), "=d" (edx)
+ : "0" (op)
+ : "bx", "cx");
+ return edx;
+}
+
+/*
+ * Intel CPU features in CR4
+ */
+#define X86_CR4_VME 0x0001 /* enable vm86 extensions */
+#define X86_CR4_PVI 0x0002 /* virtual interrupts flag enable */
+#define X86_CR4_TSD 0x0004 /* disable time stamp at ipl 3 */
+#define X86_CR4_DE 0x0008 /* enable debugging extensions */
+#define X86_CR4_PSE 0x0010 /* enable page size extensions */
+#define X86_CR4_PAE 0x0020 /* enable physical address extensions */
+#define X86_CR4_MCE 0x0040 /* Machine check enable */
+#define X86_CR4_PGE 0x0080 /* enable global pages */
+#define X86_CR4_PCE 0x0100 /* enable performance counters at ipl 3 */
+#define X86_CR4_OSFXSR 0x0200 /* enable fast FPU save and restore */
+#define X86_CR4_OSXMMEXCPT 0x0400 /* enable unmasked SSE exceptions */
+
+#define load_cr3(pgdir) \
+ asm volatile("movl %0,%%cr3": :"r" (__pa(pgdir)));
+
+extern unsigned long mmu_cr4_features;
+
+#include <asm/hypervisor.h>
+
+static inline void set_in_cr4 (unsigned long mask)
+{
+ HYPERVISOR_console_write("No set_in_cr4", 13);
+}
+
+static inline void clear_in_cr4 (unsigned long mask)
+{
+ HYPERVISOR_console_write("No clear_in_cr4", 15);
+}
+
+/*
+ * Cyrix CPU configuration register indexes
+ */
+#define CX86_CCR0 0xc0
+#define CX86_CCR1 0xc1
+#define CX86_CCR2 0xc2
+#define CX86_CCR3 0xc3
+#define CX86_CCR4 0xe8
+#define CX86_CCR5 0xe9
+#define CX86_CCR6 0xea
+#define CX86_CCR7 0xeb
+#define CX86_DIR0 0xfe
+#define CX86_DIR1 0xff
+#define CX86_ARR_BASE 0xc4
+#define CX86_RCR_BASE 0xdc
+
+/*
+ * Cyrix CPU indexed register access macros
+ */
+
+#define getCx86(reg) ({ outb((reg), 0x22); inb(0x23); })
+
+#define setCx86(reg, data) do { \
+ outb((reg), 0x22); \
+ outb((data), 0x23); \
+} while (0)
+
+/*
+ * Bus types (default is ISA, but people can check others with these..)
+ */
+#ifdef CONFIG_EISA
+extern int EISA_bus;
+#else
+#define EISA_bus (0)
+#endif
+extern int MCA_bus;
+
+/* from system description table in BIOS. Mostly for MCA use, but
+others may find it useful. */
+extern unsigned int machine_id;
+extern unsigned int machine_submodel_id;
+extern unsigned int BIOS_revision;
+extern unsigned int mca_pentium_flag;
+
+/*
+ * User space process size: 3GB (default).
+ */
+#define TASK_SIZE (PAGE_OFFSET)
+
+/* This decides where the kernel will search for a free chunk of vm
+ * space during mmap's.
+ */
+#define TASK_UNMAPPED_BASE (TASK_SIZE / 3)
+
+/*
+ * Size of io_bitmap in longwords: 32 is ports 0-0x3ff.
+ */
+#define IO_BITMAP_SIZE 32
+#define IO_BITMAP_BYTES (IO_BITMAP_SIZE * 4)
+#define IO_BITMAP_OFFSET offsetof(struct tss_struct,io_bitmap)
+#define INVALID_IO_BITMAP_OFFSET 0x8000
+
+struct i387_fsave_struct {
+ long cwd;
+ long swd;
+ long twd;
+ long fip;
+ long fcs;
+ long foo;
+ long fos;
+ long st_space[20]; /* 8*10 bytes for each FP-reg = 80 bytes */
+ long status; /* software status information */
+};
+
+struct i387_fxsave_struct {
+ unsigned short cwd;
+ unsigned short swd;
+ unsigned short twd;
+ unsigned short fop;
+ long fip;
+ long fcs;
+ long foo;
+ long fos;
+ long mxcsr;
+ long reserved;
+ long st_space[32]; /* 8*16 bytes for each FP-reg = 128 bytes */
+ long xmm_space[32]; /* 8*16 bytes for each XMM-reg = 128 bytes */
+ long padding[56];
+} __attribute__ ((aligned (16)));
+
+struct i387_soft_struct {
+ long cwd;
+ long swd;
+ long twd;
+ long fip;
+ long fcs;
+ long foo;
+ long fos;
+ long st_space[20]; /* 8*10 bytes for each FP-reg = 80 bytes */
+ unsigned char ftop, changed, lookahead, no_update, rm, alimit;
+ struct info *info;
+ unsigned long entry_eip;
+};
+
+union i387_union {
+ struct i387_fsave_struct fsave;
+ struct i387_fxsave_struct fxsave;
+ struct i387_soft_struct soft;
+};
+
+typedef struct {
+ unsigned long seg;
+} mm_segment_t;
+
+struct tss_struct {
+ unsigned short back_link,__blh;
+ unsigned long esp0;
+ unsigned short ss0,__ss0h;
+ unsigned long esp1;
+ unsigned short ss1,__ss1h;
+ unsigned long esp2;
+ unsigned short ss2,__ss2h;
+ unsigned long __cr3;
+ unsigned long eip;
+ unsigned long eflags;
+ unsigned long eax,ecx,edx,ebx;
+ unsigned long esp;
+ unsigned long ebp;
+ unsigned long esi;
+ unsigned long edi;
+ unsigned short es, __esh;
+ unsigned short cs, __csh;
+ unsigned short ss, __ssh;
+ unsigned short ds, __dsh;
+ unsigned short fs, __fsh;
+ unsigned short gs, __gsh;
+ unsigned short ldt, __ldth;
+ unsigned short trace, bitmap;
+ unsigned long io_bitmap[IO_BITMAP_SIZE+1];
+ /*
+ * pads the TSS to be cacheline-aligned (size is 0x100)
+ */
+ unsigned long __cacheline_filler[5];
+};
+
+struct thread_struct {
+ unsigned long esp0;
+ unsigned long eip;
+ unsigned long esp;
+ unsigned long fs;
+ unsigned long gs;
+ unsigned int io_pl, hypercall_pl;
+/* Hardware debugging registers */
+ unsigned long debugreg[8]; /* %%db0-7 debug registers */
+/* fault info */
+ unsigned long cr2, trap_no, error_code;
+/* floating point info */
+ union i387_union i387;
+/* virtual 86 mode info */
+ struct vm86_struct * vm86_info;
+ unsigned long screen_bitmap;
+ unsigned long v86flags, v86mask, saved_esp0;
+};
+
+#define INIT_THREAD { sizeof(init_stack) + (long) &init_stack, \
+ 0, 0, 0, 0, 0, 0, {0}, 0, 0, 0, {0}, 0, 0, 0, 0, 0 }
+
+#define INIT_TSS { \
+ 0,0, /* back_link, __blh */ \
+ sizeof(init_stack) + (long) &init_stack, /* esp0 */ \
+ __KERNEL_DS, 0, /* ss0 */ \
+ 0,0,0,0,0,0, /* stack1, stack2 */ \
+ 0, /* cr3 */ \
+ 0,0, /* eip,eflags */ \
+ 0,0,0,0, /* eax,ecx,edx,ebx */ \
+ 0,0,0,0, /* esp,ebp,esi,edi */ \
+ 0,0,0,0,0,0, /* es,cs,ss */ \
+ 0,0,0,0,0,0, /* ds,fs,gs */ \
+ 0,0, /* ldt */ \
+ 0, INVALID_IO_BITMAP_OFFSET, /* tace, bitmap */ \
+ {~0, } /* ioperm */ \
+}
+
+#define start_thread(regs, new_eip, new_esp) do { \
+ __asm__("movl %0,%%fs ; movl %0,%%gs": :"r" (0)); \
+ set_fs(USER_DS); \
+ regs->xds = __USER_DS; \
+ regs->xes = __USER_DS; \
+ regs->xss = __USER_DS; \
+ regs->xcs = __USER_CS; \
+ regs->eip = new_eip; \
+ regs->esp = new_esp; \
+} while (0)
+
+/* Forward declaration, a strange C thing */
+struct task_struct;
+struct mm_struct;
+
+/* Free all resources held by a thread. */
+extern void release_thread(struct task_struct *);
+/*
+ * create a kernel thread without removing it from tasklists
+ */
+extern int arch_kernel_thread(int (*fn)(void *), void * arg, unsigned long flags);
+
+/* Copy and release all segment info associated with a VM */
+extern void copy_segments(struct task_struct *p, struct mm_struct * mm);
+extern void release_segments(struct mm_struct * mm);
+
+/*
+ * Return saved PC of a blocked thread.
+ */
+static inline unsigned long thread_saved_pc(struct thread_struct *t)
+{
+ return ((unsigned long *)t->esp)[3];
+}
+
+unsigned long get_wchan(struct task_struct *p);
+#define KSTK_EIP(tsk) (((unsigned long *)(4096+(unsigned long)(tsk)))[1019])
+#define KSTK_ESP(tsk) (((unsigned long *)(4096+(unsigned long)(tsk)))[1022])
+
+#define THREAD_SIZE (2*PAGE_SIZE)
+#define alloc_task_struct() ((struct task_struct *) __get_free_pages(GFP_KERNEL,1))
+#define free_task_struct(p) free_pages((unsigned long) (p), 1)
+#define get_task_struct(tsk) atomic_inc(&virt_to_page(tsk)->count)
+
+#define init_task (init_task_union.task)
+#define init_stack (init_task_union.stack)
+
+struct microcode {
+ unsigned int hdrver;
+ unsigned int rev;
+ unsigned int date;
+ unsigned int sig;
+ unsigned int cksum;
+ unsigned int ldrver;
+ unsigned int pf;
+ unsigned int reserved[5];
+ unsigned int bits[500];
+};
+
+/* '6' because it used to be for P6 only (but now covers Pentium 4 as well) */
+#define MICROCODE_IOCFREE _IO('6',0)
+
+/* REP NOP (PAUSE) is a good thing to insert into busy-wait loops. */
+static inline void rep_nop(void)
+{
+ __asm__ __volatile__("rep;nop");
+}
+
+#define cpu_relax() rep_nop()
+
+/* Prefetch instructions for Pentium III and AMD Athlon */
+#if defined(CONFIG_MPENTIUMIII) || defined (CONFIG_MPENTIUM4)
+
+#define ARCH_HAS_PREFETCH
+extern inline void prefetch(const void *x)
+{
+ __asm__ __volatile__ ("prefetchnta (%0)" : : "r"(x));
+}
+
+#elif CONFIG_X86_USE_3DNOW
+
+#define ARCH_HAS_PREFETCH
+#define ARCH_HAS_PREFETCHW
+#define ARCH_HAS_SPINLOCK_PREFETCH
+
+extern inline void prefetch(const void *x)
+{
+ __asm__ __volatile__ ("prefetch (%0)" : : "r"(x));
+}
+
+extern inline void prefetchw(const void *x)
+{
+ __asm__ __volatile__ ("prefetchw (%0)" : : "r"(x));
+}
+#define spin_lock_prefetch(x) prefetchw(x)
+
+#endif
+
+#define TF_MASK 0x100
+
+#endif /* __ASM_I386_PROCESSOR_H */
--- /dev/null
+#ifndef _I386_PTRACE_H
+#define _I386_PTRACE_H
+
+#define EBX 0
+#define ECX 1
+#define EDX 2
+#define ESI 3
+#define EDI 4
+#define EBP 5
+#define EAX 6
+#define DS 7
+#define ES 8
+#define FS 9
+#define GS 10
+#define ORIG_EAX 11
+#define EIP 12
+#define CS 13
+#define EFL 14
+#define UESP 15
+#define SS 16
+#define FRAME_SIZE 17
+
+/* this struct defines the way the registers are stored on the
+ stack during a system call. */
+
+struct pt_regs {
+ long ebx;
+ long ecx;
+ long edx;
+ long esi;
+ long edi;
+ long ebp;
+ long eax;
+ int xds;
+ int xes;
+ long orig_eax;
+ long eip;
+ int xcs;
+ long eflags;
+ long esp;
+ int xss;
+};
+
+/* Arbitrarily choose the same ptrace numbers as used by the Sparc code. */
+#define PTRACE_GETREGS 12
+#define PTRACE_SETREGS 13
+#define PTRACE_GETFPREGS 14
+#define PTRACE_SETFPREGS 15
+#define PTRACE_GETFPXREGS 18
+#define PTRACE_SETFPXREGS 19
+
+#define PTRACE_SETOPTIONS 21
+
+/* options set using PTRACE_SETOPTIONS */
+#define PTRACE_O_TRACESYSGOOD 0x00000001
+
+#ifdef __KERNEL__
+#define user_mode(regs) ((regs) && (2 & (regs)->xcs))
+#define instruction_pointer(regs) ((regs) ? (regs)->eip : NULL)
+extern void show_regs(struct pt_regs *);
+#endif
+
+#endif
--- /dev/null
+#ifndef _ASM_SEGMENT_H
+#define _ASM_SEGMENT_H
+
+#include <asm/hypervisor-ifs/hypervisor-if.h>
+
+#define __KERNEL_CS FLAT_RING1_CS
+#define __KERNEL_DS FLAT_RING1_DS
+
+#define __USER_CS FLAT_RING3_CS
+#define __USER_DS FLAT_RING3_DS
+
+#endif
--- /dev/null
+#ifndef __ASM_SMP_H
+#define __ASM_SMP_H
+
+/*
+ * We need the APIC definitions automatically as part of 'smp.h'
+ */
+#ifndef __ASSEMBLY__
+#include <linux/config.h>
+#include <linux/threads.h>
+#include <linux/ptrace.h>
+#endif
+
+#ifdef CONFIG_X86_LOCAL_APIC
+#ifndef __ASSEMBLY__
+#include <asm/bitops.h>
+#include <asm/mpspec.h>
+#ifdef CONFIG_X86_IO_APIC
+#include <asm/io_apic.h>
+#endif
+#include <asm/apic.h>
+#endif
+#endif
+
+#ifdef CONFIG_SMP
+#ifndef __ASSEMBLY__
+
+/*
+ * Private routines/data
+ */
+
+extern void smp_alloc_memory(void);
+extern unsigned long phys_cpu_present_map;
+extern unsigned long cpu_online_map;
+extern volatile unsigned long smp_invalidate_needed;
+extern int pic_mode;
+extern int smp_num_siblings;
+extern int cpu_sibling_map[];
+
+extern void smp_flush_tlb(void);
+extern void smp_message_irq(int cpl, void *dev_id, struct pt_regs *regs);
+extern void smp_send_reschedule(int cpu);
+extern void smp_invalidate_rcv(void); /* Process an NMI */
+extern void (*mtrr_hook) (void);
+extern void zap_low_mappings (void);
+
+/*
+ * On x86 all CPUs are mapped 1:1 to the APIC space.
+ * This simplifies scheduling and IPI sending and
+ * compresses data structures.
+ */
+static inline int cpu_logical_map(int cpu)
+{
+ return cpu;
+}
+static inline int cpu_number_map(int cpu)
+{
+ return cpu;
+}
+
+/*
+ * Some lowlevel functions might want to know about
+ * the real APIC ID <-> CPU # mapping.
+ */
+#define MAX_APICID 256
+extern volatile int cpu_to_physical_apicid[NR_CPUS];
+extern volatile int physical_apicid_to_cpu[MAX_APICID];
+extern volatile int cpu_to_logical_apicid[NR_CPUS];
+extern volatile int logical_apicid_to_cpu[MAX_APICID];
+
+/*
+ * General functions that each host system must provide.
+ */
+
+extern void smp_boot_cpus(void);
+extern void smp_store_cpu_info(int id); /* Store per CPU info (like the initial udelay numbers */
+
+/*
+ * This function is needed by all SMP systems. It must _always_ be valid
+ * from the initial startup. We map APIC_BASE very early in page_setup(),
+ * so this is correct in the x86 case.
+ */
+
+#define smp_processor_id() (current->processor)
+
+#endif /* !__ASSEMBLY__ */
+
+#define NO_PROC_ID 0xFF /* No processor magic marker */
+
+/*
+ * This magic constant controls our willingness to transfer
+ * a process across CPUs. Such a transfer incurs misses on the L1
+ * cache, and on a P6 or P5 with multiple L2 caches L2 hits. My
+ * gut feeling is this will vary by board in value. For a board
+ * with separate L2 cache it probably depends also on the RSS, and
+ * for a board with shared L2 cache it ought to decay fast as other
+ * processes are run.
+ */
+
+#define PROC_CHANGE_PENALTY 15 /* Schedule penalty */
+
+#endif
+#endif
--- /dev/null
+#ifndef __ASM_SYSTEM_H
+#define __ASM_SYSTEM_H
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <asm/segment.h>
+#include <asm/hypervisor.h>
+#include <linux/bitops.h> /* for LOCK_PREFIX */
+
+#ifdef __KERNEL__
+
+struct task_struct;
+extern void FASTCALL(__switch_to(struct task_struct *prev,
+ struct task_struct *next));
+
+#define prepare_to_switch() \
+do { \
+ struct thread_struct *__t = ¤t->thread; \
+ __asm__ __volatile__ ( "movl %%fs,%0" : "=m" (*(int *)&__t->fs) ); \
+ __asm__ __volatile__ ( "movl %%gs,%0" : "=m" (*(int *)&__t->gs) ); \
+} while (0)
+#define switch_to(prev,next,last) do { \
+ asm volatile("pushl %%esi\n\t" \
+ "pushl %%edi\n\t" \
+ "pushl %%ebp\n\t" \
+ "movl %%esp,%0\n\t" /* save ESP */ \
+ "movl %3,%%esp\n\t" /* restore ESP */ \
+ "movl $1f,%1\n\t" /* save EIP */ \
+ "pushl %4\n\t" /* restore EIP */ \
+ "jmp __switch_to\n" \
+ "1:\t" \
+ "popl %%ebp\n\t" \
+ "popl %%edi\n\t" \
+ "popl %%esi\n\t" \
+ :"=m" (prev->thread.esp),"=m" (prev->thread.eip), \
+ "=b" (last) \
+ :"m" (next->thread.esp),"m" (next->thread.eip), \
+ "a" (prev), "d" (next), \
+ "b" (prev)); \
+} while (0)
+
+#define _set_base(addr,base) do { unsigned long __pr; \
+__asm__ __volatile__ ("movw %%dx,%1\n\t" \
+ "rorl $16,%%edx\n\t" \
+ "movb %%dl,%2\n\t" \
+ "movb %%dh,%3" \
+ :"=&d" (__pr) \
+ :"m" (*((addr)+2)), \
+ "m" (*((addr)+4)), \
+ "m" (*((addr)+7)), \
+ "0" (base) \
+ ); } while(0)
+
+#define _set_limit(addr,limit) do { unsigned long __lr; \
+__asm__ __volatile__ ("movw %%dx,%1\n\t" \
+ "rorl $16,%%edx\n\t" \
+ "movb %2,%%dh\n\t" \
+ "andb $0xf0,%%dh\n\t" \
+ "orb %%dh,%%dl\n\t" \
+ "movb %%dl,%2" \
+ :"=&d" (__lr) \
+ :"m" (*(addr)), \
+ "m" (*((addr)+6)), \
+ "0" (limit) \
+ ); } while(0)
+
+#define set_base(ldt,base) _set_base( ((char *)&(ldt)) , (base) )
+#define set_limit(ldt,limit) _set_limit( ((char *)&(ldt)) , ((limit)-1)>>12 )
+
+static inline unsigned long _get_base(char * addr)
+{
+ unsigned long __base;
+ __asm__("movb %3,%%dh\n\t"
+ "movb %2,%%dl\n\t"
+ "shll $16,%%edx\n\t"
+ "movw %1,%%dx"
+ :"=&d" (__base)
+ :"m" (*((addr)+2)),
+ "m" (*((addr)+4)),
+ "m" (*((addr)+7)));
+ return __base;
+}
+
+#define get_base(ldt) _get_base( ((char *)&(ldt)) )
+
+/*
+ * Load a segment. Fall back on loading the zero
+ * segment if something goes wrong..
+ */
+#define loadsegment(seg,value) \
+ asm volatile("\n" \
+ "1:\t" \
+ "movl %0,%%" #seg "\n" \
+ "2:\n" \
+ ".section .fixup,\"ax\"\n" \
+ "3:\t" \
+ "pushl $0\n\t" \
+ "popl %%" #seg "\n\t" \
+ "jmp 2b\n" \
+ ".previous\n" \
+ ".section __ex_table,\"a\"\n\t" \
+ ".align 4\n\t" \
+ ".long 1b,3b\n" \
+ ".previous" \
+ : :"m" (*(unsigned int *)&(value)))
+
+#define clts() ((void)0)
+#define read_cr0() ({ \
+ unsigned int __dummy; \
+ __asm__( \
+ "movl %%cr0,%0\n\t" \
+ :"=r" (__dummy)); \
+ __dummy; \
+})
+#define write_cr0(x) \
+ __asm__("movl %0,%%cr0": :"r" (x));
+
+#define read_cr4() ({ \
+ unsigned int __dummy; \
+ __asm__( \
+ "movl %%cr4,%0\n\t" \
+ :"=r" (__dummy)); \
+ __dummy; \
+})
+#define write_cr4(x) \
+ __asm__("movl %0,%%cr4": :"r" (x));
+#define stts() (HYPERVISOR_fpu_taskswitch())
+
+#endif /* __KERNEL__ */
+
+#define wbinvd() \
+ __asm__ __volatile__ ("wbinvd": : :"memory");
+
+static inline unsigned long get_limit(unsigned long segment)
+{
+ unsigned long __limit;
+ __asm__("lsll %1,%0"
+ :"=r" (__limit):"r" (segment));
+ return __limit+1;
+}
+
+#define nop() __asm__ __volatile__ ("nop")
+
+#define xchg(ptr,v) ((__typeof__(*(ptr)))__xchg((unsigned long)(v),(ptr),sizeof(*(ptr))))
+
+#define tas(ptr) (xchg((ptr),1))
+
+struct __xchg_dummy { unsigned long a[100]; };
+#define __xg(x) ((struct __xchg_dummy *)(x))
+
+
+/*
+ * The semantics of XCHGCMP8B are a bit strange, this is why
+ * there is a loop and the loading of %%eax and %%edx has to
+ * be inside. This inlines well in most cases, the cached
+ * cost is around ~38 cycles. (in the future we might want
+ * to do an SIMD/3DNOW!/MMX/FPU 64-bit store here, but that
+ * might have an implicit FPU-save as a cost, so it's not
+ * clear which path to go.)
+ *
+ * chmxchg8b must be used with the lock prefix here to allow
+ * the instruction to be executed atomically, see page 3-102
+ * of the instruction set reference 24319102.pdf. We need
+ * the reader side to see the coherent 64bit value.
+ */
+static inline void __set_64bit (unsigned long long * ptr,
+ unsigned int low, unsigned int high)
+{
+ __asm__ __volatile__ (
+ "\n1:\t"
+ "movl (%0), %%eax\n\t"
+ "movl 4(%0), %%edx\n\t"
+ "lock cmpxchg8b (%0)\n\t"
+ "jnz 1b"
+ : /* no outputs */
+ : "D"(ptr),
+ "b"(low),
+ "c"(high)
+ : "ax","dx","memory");
+}
+
+static inline void __set_64bit_constant (unsigned long long *ptr,
+ unsigned long long value)
+{
+ __set_64bit(ptr,(unsigned int)(value), (unsigned int)((value)>>32ULL));
+}
+#define ll_low(x) *(((unsigned int*)&(x))+0)
+#define ll_high(x) *(((unsigned int*)&(x))+1)
+
+static inline void __set_64bit_var (unsigned long long *ptr,
+ unsigned long long value)
+{
+ __set_64bit(ptr,ll_low(value), ll_high(value));
+}
+
+#define set_64bit(ptr,value) \
+(__builtin_constant_p(value) ? \
+ __set_64bit_constant(ptr, value) : \
+ __set_64bit_var(ptr, value) )
+
+#define _set_64bit(ptr,value) \
+(__builtin_constant_p(value) ? \
+ __set_64bit(ptr, (unsigned int)(value), (unsigned int)((value)>>32ULL) ) : \
+ __set_64bit(ptr, ll_low(value), ll_high(value)) )
+
+/*
+ * Note: no "lock" prefix even on SMP: xchg always implies lock anyway
+ * Note 2: xchg has side effect, so that attribute volatile is necessary,
+ * but generally the primitive is invalid, *ptr is output argument. --ANK
+ */
+static inline unsigned long __xchg(unsigned long x, volatile void * ptr, int size)
+{
+ switch (size) {
+ case 1:
+ __asm__ __volatile__("xchgb %b0,%1"
+ :"=q" (x)
+ :"m" (*__xg(ptr)), "0" (x)
+ :"memory");
+ break;
+ case 2:
+ __asm__ __volatile__("xchgw %w0,%1"
+ :"=r" (x)
+ :"m" (*__xg(ptr)), "0" (x)
+ :"memory");
+ break;
+ case 4:
+ __asm__ __volatile__("xchgl %0,%1"
+ :"=r" (x)
+ :"m" (*__xg(ptr)), "0" (x)
+ :"memory");
+ break;
+ }
+ return x;
+}
+
+/*
+ * Atomic compare and exchange. Compare OLD with MEM, if identical,
+ * store NEW in MEM. Return the initial value in MEM. Success is
+ * indicated by comparing RETURN with OLD.
+ */
+
+#ifdef CONFIG_X86_CMPXCHG
+#define __HAVE_ARCH_CMPXCHG 1
+
+static inline unsigned long __cmpxchg(volatile void *ptr, unsigned long old,
+ unsigned long new, int size)
+{
+ unsigned long prev;
+ switch (size) {
+ case 1:
+ __asm__ __volatile__(LOCK_PREFIX "cmpxchgb %b1,%2"
+ : "=a"(prev)
+ : "q"(new), "m"(*__xg(ptr)), "0"(old)
+ : "memory");
+ return prev;
+ case 2:
+ __asm__ __volatile__(LOCK_PREFIX "cmpxchgw %w1,%2"
+ : "=a"(prev)
+ : "q"(new), "m"(*__xg(ptr)), "0"(old)
+ : "memory");
+ return prev;
+ case 4:
+ __asm__ __volatile__(LOCK_PREFIX "cmpxchgl %1,%2"
+ : "=a"(prev)
+ : "q"(new), "m"(*__xg(ptr)), "0"(old)
+ : "memory");
+ return prev;
+ }
+ return old;
+}
+
+#define cmpxchg(ptr,o,n)\
+ ((__typeof__(*(ptr)))__cmpxchg((ptr),(unsigned long)(o),\
+ (unsigned long)(n),sizeof(*(ptr))))
+
+#else
+/* Compiling for a 386 proper. Is it worth implementing via cli/sti? */
+#endif
+
+/*
+ * Force strict CPU ordering.
+ * And yes, this is required on UP too when we're talking
+ * to devices.
+ *
+ * For now, "wmb()" doesn't actually do anything, as all
+ * Intel CPU's follow what Intel calls a *Processor Order*,
+ * in which all writes are seen in the program order even
+ * outside the CPU.
+ *
+ * I expect future Intel CPU's to have a weaker ordering,
+ * but I'd also expect them to finally get their act together
+ * and add some real memory barriers if so.
+ *
+ * Some non intel clones support out of order store. wmb() ceases to be a
+ * nop for these.
+ */
+
+#define mb() __asm__ __volatile__ ("lock; addl $0,0(%%esp)": : :"memory")
+#define rmb() mb()
+
+#ifdef CONFIG_X86_OOSTORE
+#define wmb() __asm__ __volatile__ ("lock; addl $0,0(%%esp)": : :"memory")
+#else
+#define wmb() __asm__ __volatile__ ("": : :"memory")
+#endif
+
+#ifdef CONFIG_SMP
+#define smp_mb() mb()
+#define smp_rmb() rmb()
+#define smp_wmb() wmb()
+#define set_mb(var, value) do { xchg(&var, value); } while (0)
+#else
+#define smp_mb() barrier()
+#define smp_rmb() barrier()
+#define smp_wmb() barrier()
+#define set_mb(var, value) do { var = value; barrier(); } while (0)
+#endif
+
+#define set_wmb(var, value) do { var = value; wmb(); } while (0)
+
+
+#define __save_flags(x) \
+do { \
+ (x) = test_bit(EVENTS_MASTER_ENABLE_BIT, \
+ &HYPERVISOR_shared_info->events_mask); \
+ barrier(); \
+} while (0)
+
+#define __restore_flags(x) \
+do { \
+ shared_info_t *_shared = HYPERVISOR_shared_info; \
+ if (x) set_bit(EVENTS_MASTER_ENABLE_BIT, &_shared->events_mask); \
+ barrier(); \
+ if ( unlikely(_shared->events) && (x) ) do_hypervisor_callback(NULL); \
+} while (0)
+
+#define __cli() \
+do { \
+ clear_bit(EVENTS_MASTER_ENABLE_BIT, &HYPERVISOR_shared_info->events_mask);\
+ barrier(); \
+} while (0)
+
+#define __sti() \
+do { \
+ shared_info_t *_shared = HYPERVISOR_shared_info; \
+ set_bit(EVENTS_MASTER_ENABLE_BIT, &_shared->events_mask); \
+ barrier(); \
+ if ( unlikely(_shared->events) ) do_hypervisor_callback(NULL); \
+} while (0)
+
+#define safe_halt() ((void)0)
+
+#define __save_and_cli(x) do { __save_flags(x); __cli(); } while(0);
+#define __save_and_sti(x) do { __save_flags(x); __sti(); } while(0);
+
+#define local_irq_save(x) \
+do { \
+ (x) = test_and_clear_bit(EVENTS_MASTER_ENABLE_BIT, \
+ &HYPERVISOR_shared_info->events_mask); \
+ barrier(); \
+} while (0)
+#define local_irq_restore(x) __restore_flags(x)
+#define local_irq_disable() __cli()
+#define local_irq_enable() __sti()
+
+
+#ifdef CONFIG_SMP
+#error no SMP
+extern void __global_cli(void);
+extern void __global_sti(void);
+extern unsigned long __global_save_flags(void);
+extern void __global_restore_flags(unsigned long);
+#define cli() __global_cli()
+#define sti() __global_sti()
+#define save_flags(x) ((x)=__global_save_flags())
+#define restore_flags(x) __global_restore_flags(x)
+#define save_and_cli(x) do { save_flags(x); cli(); } while(0);
+#define save_and_sti(x) do { save_flags(x); sti(); } while(0);
+
+#else
+
+#define cli() __cli()
+#define sti() __sti()
+#define save_flags(x) __save_flags(x)
+#define restore_flags(x) __restore_flags(x)
+#define save_and_cli(x) __save_and_cli(x)
+#define save_and_sti(x) __save_and_sti(x)
+
+#endif
+
+/*
+ * disable hlt during certain critical i/o operations
+ */
+#define HAVE_DISABLE_HLT
+void disable_hlt(void);
+void enable_hlt(void);
+
+extern unsigned long dmi_broken;
+extern int is_sony_vaio_laptop;
+
+#define BROKEN_ACPI_Sx 0x0001
+#define BROKEN_INIT_AFTER_S1 0x0002
+
+#endif
--- /dev/null
+#ifndef _LINUX_MAJOR_H
+#define _LINUX_MAJOR_H
+
+/*
+ * This file has definitions for major device numbers.
+ * For the device number assignments, see Documentation/devices.txt.
+ */
+
+/* limits */
+
+/*
+ * Important: Don't change this to 256. Major number 255 is and must be
+ * reserved for future expansion into a larger dev_t space.
+ */
+#define MAX_CHRDEV 255
+#define MAX_BLKDEV 255
+
+#define UNNAMED_MAJOR 0
+#define MEM_MAJOR 1
+#define RAMDISK_MAJOR 1
+#define FLOPPY_MAJOR 2
+#define PTY_MASTER_MAJOR 2
+#define IDE0_MAJOR 3
+#define PTY_SLAVE_MAJOR 3
+#define HD_MAJOR IDE0_MAJOR
+#define TTY_MAJOR 4
+#define TTYAUX_MAJOR 5
+#define LP_MAJOR 6
+#define VCS_MAJOR 7
+#define LOOP_MAJOR 7
+#define SCSI_DISK0_MAJOR 8
+#define SCSI_TAPE_MAJOR 9
+#define MD_MAJOR 9
+#define MISC_MAJOR 10
+#define SCSI_CDROM_MAJOR 11
+#define MUX_MAJOR 11 /* PA-RISC only */
+#define QIC02_TAPE_MAJOR 12
+#define XT_DISK_MAJOR 13
+#define SOUND_MAJOR 14
+#define CDU31A_CDROM_MAJOR 15
+#define JOYSTICK_MAJOR 15
+#define GOLDSTAR_CDROM_MAJOR 16
+#define OPTICS_CDROM_MAJOR 17
+#define SANYO_CDROM_MAJOR 18
+#define CYCLADES_MAJOR 19
+#define CYCLADESAUX_MAJOR 20
+#define MITSUMI_X_CDROM_MAJOR 20
+#define MFM_ACORN_MAJOR 21 /* ARM Linux /dev/mfm */
+#define SCSI_GENERIC_MAJOR 21
+#define Z8530_MAJOR 34
+#define DIGI_MAJOR 23
+#define IDE1_MAJOR 22
+#define DIGICU_MAJOR 22
+#define MITSUMI_CDROM_MAJOR 23
+#define CDU535_CDROM_MAJOR 24
+#define STL_SERIALMAJOR 24
+#define MATSUSHITA_CDROM_MAJOR 25
+#define STL_CALLOUTMAJOR 25
+#define MATSUSHITA_CDROM2_MAJOR 26
+#define QIC117_TAPE_MAJOR 27
+#define MATSUSHITA_CDROM3_MAJOR 27
+#define MATSUSHITA_CDROM4_MAJOR 28
+#define STL_SIOMEMMAJOR 28
+#define ACSI_MAJOR 28
+#define AZTECH_CDROM_MAJOR 29
+#define GRAPHDEV_MAJOR 29 /* SparcLinux & Linux/68k /dev/fb */
+#define SHMIQ_MAJOR 85 /* Linux/mips, SGI /dev/shmiq */
+#define CM206_CDROM_MAJOR 32
+#define IDE2_MAJOR 33
+#define IDE3_MAJOR 34
+#define XPRAM_MAJOR 35 /* expanded storage on S/390 = "slow ram" */
+ /* proposed by Peter */
+#define NETLINK_MAJOR 36
+#define PS2ESDI_MAJOR 36
+#define IDETAPE_MAJOR 37
+#define Z2RAM_MAJOR 37
+#define APBLOCK_MAJOR 38 /* AP1000 Block device */
+#define DDV_MAJOR 39 /* AP1000 DDV block device */
+#define NBD_MAJOR 43 /* Network block device */
+#define RISCOM8_NORMAL_MAJOR 48
+#define DAC960_MAJOR 48 /* 48..55 */
+#define RISCOM8_CALLOUT_MAJOR 49
+#define MKISS_MAJOR 55
+#define DSP56K_MAJOR 55 /* DSP56001 processor device */
+
+#define IDE4_MAJOR 56
+#define IDE5_MAJOR 57
+
+#define LVM_BLK_MAJOR 58 /* Logical Volume Manager */
+
+#define SCSI_DISK1_MAJOR 65
+#define SCSI_DISK2_MAJOR 66
+#define SCSI_DISK3_MAJOR 67
+#define SCSI_DISK4_MAJOR 68
+#define SCSI_DISK5_MAJOR 69
+#define SCSI_DISK6_MAJOR 70
+#define SCSI_DISK7_MAJOR 71
+
+
+#define COMPAQ_SMART2_MAJOR 72
+#define COMPAQ_SMART2_MAJOR1 73
+#define COMPAQ_SMART2_MAJOR2 74
+#define COMPAQ_SMART2_MAJOR3 75
+#define COMPAQ_SMART2_MAJOR4 76
+#define COMPAQ_SMART2_MAJOR5 77
+#define COMPAQ_SMART2_MAJOR6 78
+#define COMPAQ_SMART2_MAJOR7 79
+
+#define SPECIALIX_NORMAL_MAJOR 75
+#define SPECIALIX_CALLOUT_MAJOR 76
+
+#define COMPAQ_CISS_MAJOR 104
+#define COMPAQ_CISS_MAJOR1 105
+#define COMPAQ_CISS_MAJOR2 106
+#define COMPAQ_CISS_MAJOR3 107
+#define COMPAQ_CISS_MAJOR4 108
+#define COMPAQ_CISS_MAJOR5 109
+#define COMPAQ_CISS_MAJOR6 110
+#define COMPAQ_CISS_MAJOR7 111
+
+#define ATARAID_MAJOR 114
+
+#define DASD_MAJOR 94 /* Official assignations from Peter */
+
+#define MDISK_MAJOR 95 /* Official assignations from Peter */
+
+#define I2O_MAJOR 80 /* 80->87 */
+
+#define IDE6_MAJOR 88
+#define IDE7_MAJOR 89
+#define IDE8_MAJOR 90
+#define IDE9_MAJOR 91
+
+#define UBD_MAJOR 98
+
+#define AURORA_MAJOR 79
+
+#define JSFD_MAJOR 99
+
+#define PHONE_MAJOR 100
+
+#define LVM_CHAR_MAJOR 109 /* Logical Volume Manager */
+
+#define UMEM_MAJOR 116 /* http://www.umem.com/ Battery Backed RAM */
+
+#define UMEM_MAJOR 116 /* http://www.umem.com/ Battery Backed RAM */
+
+/*
+ * XLVIRT supports 16 devices of <= 16 partitions each.
+ * eg. xvda == (125, 0), xvdb == (125, 16), ...
+ */
+#define XLVIRT_MAJOR 125
+
+#define RTF_MAJOR 150
+#define RAW_MAJOR 162
+
+#define USB_ACM_MAJOR 166
+#define USB_ACM_AUX_MAJOR 167
+#define USB_CHAR_MAJOR 180
+
+#define UNIX98_PTY_MASTER_MAJOR 128
+#define UNIX98_PTY_MAJOR_COUNT 8
+#define UNIX98_PTY_SLAVE_MAJOR (UNIX98_PTY_MASTER_MAJOR+UNIX98_PTY_MAJOR_COUNT)
+
+#define VXVM_MAJOR 199 /* VERITAS volume i/o driver */
+#define VXSPEC_MAJOR 200 /* VERITAS volume config driver */
+#define VXDMP_MAJOR 201 /* VERITAS volume multipath driver */
+
+#define MSR_MAJOR 202
+#define CPUID_MAJOR 203
+
+#define OSST_MAJOR 206 /* OnStream-SCx0 SCSI tape */
+
+#define IBM_TTY3270_MAJOR 227 /* Official allocations now */
+#define IBM_FS3270_MAJOR 228
+
+/*
+ * Tests for SCSI devices.
+ */
+
+#define SCSI_DISK_MAJOR(M) ((M) == SCSI_DISK0_MAJOR || \
+ ((M) >= SCSI_DISK1_MAJOR && (M) <= SCSI_DISK7_MAJOR))
+
+#define SCSI_BLK_MAJOR(M) \
+ (SCSI_DISK_MAJOR(M) \
+ || (M) == SCSI_CDROM_MAJOR)
+
+static __inline__ int scsi_blk_major(int m) {
+ return SCSI_BLK_MAJOR(m);
+}
+
+/*
+ * Tests for IDE devices
+ */
+#define IDE_DISK_MAJOR(M) ((M) == IDE0_MAJOR || (M) == IDE1_MAJOR || \
+ (M) == IDE2_MAJOR || (M) == IDE3_MAJOR || \
+ (M) == IDE4_MAJOR || (M) == IDE5_MAJOR || \
+ (M) == IDE6_MAJOR || (M) == IDE7_MAJOR || \
+ (M) == IDE8_MAJOR || (M) == IDE9_MAJOR)
+
+static __inline__ int ide_blk_major(int m)
+{
+ return IDE_DISK_MAJOR(m);
+}
+
+#endif
--- /dev/null
+/*
+ * linux/include/linux/sunrpc/debug.h
+ *
+ * Debugging support for sunrpc module
+ *
+ * Copyright (C) 1996, Olaf Kirch <okir@monad.swb.de>
+ */
+
+#ifndef _LINUX_SUNRPC_DEBUG_H_
+#define _LINUX_SUNRPC_DEBUG_H_
+
+#include <linux/config.h>
+
+#include <linux/timer.h>
+#include <linux/tqueue.h>
+
+/*
+ * Enable RPC debugging/profiling.
+ */
+/*#ifdef CONFIG_SYSCTL*/
+/*#define RPC_DEBUG*/
+/*#endif*/
+/* #define RPC_PROFILE */
+
+/*
+ * RPC debug facilities
+ */
+#define RPCDBG_XPRT 0x0001
+#define RPCDBG_CALL 0x0002
+#define RPCDBG_DEBUG 0x0004
+#define RPCDBG_NFS 0x0008
+#define RPCDBG_AUTH 0x0010
+#define RPCDBG_PMAP 0x0020
+#define RPCDBG_SCHED 0x0040
+#define RPCDBG_SVCSOCK 0x0100
+#define RPCDBG_SVCDSP 0x0200
+#define RPCDBG_MISC 0x0400
+#define RPCDBG_ALL 0x7fff
+
+#ifdef __KERNEL__
+
+/*
+ * Debugging macros etc
+ */
+#ifdef RPC_DEBUG
+extern unsigned int rpc_debug;
+extern unsigned int nfs_debug;
+extern unsigned int nfsd_debug;
+extern unsigned int nlm_debug;
+#endif
+
+#define dprintk(args...) dfprintk(FACILITY, ## args)
+
+#undef ifdebug
+#ifdef RPC_DEBUG
+# define ifdebug(fac) if (rpc_debug & RPCDBG_##fac)
+# define dfprintk(fac, args...) do { ifdebug(fac) printk(args); } while(0)
+# define RPC_IFDEBUG(x) x
+#else
+# define dfprintk(fac, args...) do ; while (0)
+# define RPC_IFDEBUG(x)
+#endif
+
+#ifdef RPC_PROFILE
+# define pprintk(args...) printk(## args)
+#else
+# define pprintk(args...) do ; while (0)
+#endif
+
+/*
+ * Sysctl interface for RPC debugging
+ */
+#ifdef RPC_DEBUG
+void rpc_register_sysctl(void);
+void rpc_unregister_sysctl(void);
+#endif
+
+#endif /* __KERNEL__ */
+
+/*
+ * Declarations for the sysctl debug interface, which allows to read or
+ * change the debug flags for rpc, nfs, nfsd, and lockd. Since the sunrpc
+ * module currently registers its sysctl table dynamically, the sysctl path
+ * for module FOO is <CTL_SUNRPC, CTL_FOODEBUG>.
+ */
+#define CTL_SUNRPC 7249 /* arbitrary and hopefully unused */
+
+enum {
+ CTL_RPCDEBUG = 1,
+ CTL_NFSDEBUG,
+ CTL_NFSDDEBUG,
+ CTL_NLMDEBUG,
+};
+
+#endif /* _LINUX_SUNRPC_DEBUG_H_ */
--- /dev/null
+#define __KERNEL_SYSCALLS__
+#include <linux/config.h>
+#include <linux/slab.h>
+#include <linux/devfs_fs_kernel.h>
+#include <linux/unistd.h>
+#include <linux/ctype.h>
+#include <linux/blk.h>
+#include <linux/fd.h>
+#include <linux/tty.h>
+#include <linux/init.h>
+
+#include <linux/nfs_fs.h>
+#include <linux/nfs_fs_sb.h>
+#include <linux/nfs_mount.h>
+#include <linux/minix_fs.h>
+#include <linux/ext2_fs.h>
+#include <linux/romfs_fs.h>
+
+#define BUILD_CRAMDISK
+
+extern int get_filesystem_list(char * buf);
+
+extern asmlinkage long sys_mount(char *dev_name, char *dir_name, char *type,
+ unsigned long flags, void *data);
+extern asmlinkage long sys_mkdir(const char *name, int mode);
+extern asmlinkage long sys_chdir(const char *name);
+extern asmlinkage long sys_fchdir(int fd);
+extern asmlinkage long sys_chroot(const char *name);
+extern asmlinkage long sys_unlink(const char *name);
+extern asmlinkage long sys_symlink(const char *old, const char *new);
+extern asmlinkage long sys_mknod(const char *name, int mode, dev_t dev);
+extern asmlinkage long sys_umount(char *name, int flags);
+extern asmlinkage long sys_ioctl(int fd, int cmd, unsigned long arg);
+
+#ifdef CONFIG_BLK_DEV_INITRD
+unsigned int real_root_dev; /* do_proc_dointvec cannot handle kdev_t */
+static int __initdata mount_initrd = 1;
+
+static int __init no_initrd(char *str)
+{
+ mount_initrd = 0;
+ return 1;
+}
+
+__setup("noinitrd", no_initrd);
+#else
+static int __initdata mount_initrd = 0;
+#endif
+
+int __initdata rd_doload; /* 1 = load RAM disk, 0 = don't load */
+
+int root_mountflags = MS_RDONLY | MS_VERBOSE;
+static char root_device_name[64];
+
+/* this is initialized in init/main.c */
+kdev_t ROOT_DEV;
+
+static int do_devfs = 0;
+
+static int __init load_ramdisk(char *str)
+{
+ rd_doload = simple_strtol(str,NULL,0) & 3;
+ return 1;
+}
+__setup("load_ramdisk=", load_ramdisk);
+
+static int __init readonly(char *str)
+{
+ if (*str)
+ return 0;
+ root_mountflags |= MS_RDONLY;
+ return 1;
+}
+
+static int __init readwrite(char *str)
+{
+ if (*str)
+ return 0;
+ root_mountflags &= ~MS_RDONLY;
+ return 1;
+}
+
+__setup("ro", readonly);
+__setup("rw", readwrite);
+
+static struct dev_name_struct {
+ const char *name;
+ const int num;
+} root_dev_names[] __initdata = {
+ { "nfs", 0x00ff },
+ { "hda", 0x0300 },
+ { "hdb", 0x0340 },
+ { "loop", 0x0700 },
+ { "hdc", 0x1600 },
+ { "hdd", 0x1640 },
+ { "hde", 0x2100 },
+ { "hdf", 0x2140 },
+ { "hdg", 0x2200 },
+ { "hdh", 0x2240 },
+ { "hdi", 0x3800 },
+ { "hdj", 0x3840 },
+ { "hdk", 0x3900 },
+ { "hdl", 0x3940 },
+ { "hdm", 0x5800 },
+ { "hdn", 0x5840 },
+ { "hdo", 0x5900 },
+ { "hdp", 0x5940 },
+ { "hdq", 0x5A00 },
+ { "hdr", 0x5A40 },
+ { "hds", 0x5B00 },
+ { "hdt", 0x5B40 },
+ { "sda", 0x0800 },
+ { "sdb", 0x0810 },
+ { "sdc", 0x0820 },
+ { "sdd", 0x0830 },
+ { "sde", 0x0840 },
+ { "sdf", 0x0850 },
+ { "sdg", 0x0860 },
+ { "sdh", 0x0870 },
+ { "sdi", 0x0880 },
+ { "sdj", 0x0890 },
+ { "sdk", 0x08a0 },
+ { "sdl", 0x08b0 },
+ { "sdm", 0x08c0 },
+ { "sdn", 0x08d0 },
+ { "sdo", 0x08e0 },
+ { "sdp", 0x08f0 },
+ { "ada", 0x1c00 },
+ { "adb", 0x1c10 },
+ { "adc", 0x1c20 },
+ { "add", 0x1c30 },
+ { "ade", 0x1c40 },
+ { "fd", 0x0200 },
+ { "md", 0x0900 },
+ { "xda", 0x0d00 },
+ { "xdb", 0x0d40 },
+ { "ram", 0x0100 },
+ { "scd", 0x0b00 },
+ { "mcd", 0x1700 },
+ { "cdu535", 0x1800 },
+ { "sonycd", 0x1800 },
+ { "aztcd", 0x1d00 },
+ { "cm206cd", 0x2000 },
+ { "gscd", 0x1000 },
+ { "sbpcd", 0x1900 },
+ { "eda", 0x2400 },
+ { "edb", 0x2440 },
+ { "pda", 0x2d00 },
+ { "pdb", 0x2d10 },
+ { "pdc", 0x2d20 },
+ { "pdd", 0x2d30 },
+ { "pcd", 0x2e00 },
+ { "pf", 0x2f00 },
+ { "apblock", APBLOCK_MAJOR << 8},
+ { "ddv", DDV_MAJOR << 8},
+ { "jsfd", JSFD_MAJOR << 8},
+#if defined(CONFIG_ARCH_S390)
+ { "dasda", (DASD_MAJOR << MINORBITS) },
+ { "dasdb", (DASD_MAJOR << MINORBITS) + (1 << 2) },
+ { "dasdc", (DASD_MAJOR << MINORBITS) + (2 << 2) },
+ { "dasdd", (DASD_MAJOR << MINORBITS) + (3 << 2) },
+ { "dasde", (DASD_MAJOR << MINORBITS) + (4 << 2) },
+ { "dasdf", (DASD_MAJOR << MINORBITS) + (5 << 2) },
+ { "dasdg", (DASD_MAJOR << MINORBITS) + (6 << 2) },
+ { "dasdh", (DASD_MAJOR << MINORBITS) + (7 << 2) },
+#endif
+ { "ida/c0d0p",0x4800 },
+ { "ida/c0d1p",0x4810 },
+ { "ida/c0d2p",0x4820 },
+ { "ida/c0d3p",0x4830 },
+ { "ida/c0d4p",0x4840 },
+ { "ida/c0d5p",0x4850 },
+ { "ida/c0d6p",0x4860 },
+ { "ida/c0d7p",0x4870 },
+ { "ida/c0d8p",0x4880 },
+ { "ida/c0d9p",0x4890 },
+ { "ida/c0d10p",0x48A0 },
+ { "ida/c0d11p",0x48B0 },
+ { "ida/c0d12p",0x48C0 },
+ { "ida/c0d13p",0x48D0 },
+ { "ida/c0d14p",0x48E0 },
+ { "ida/c0d15p",0x48F0 },
+ { "ida/c1d0p",0x4900 },
+ { "ida/c2d0p",0x4A00 },
+ { "ida/c3d0p",0x4B00 },
+ { "ida/c4d0p",0x4C00 },
+ { "ida/c5d0p",0x4D00 },
+ { "ida/c6d0p",0x4E00 },
+ { "ida/c7d0p",0x4F00 },
+ { "cciss/c0d0p",0x6800 },
+ { "cciss/c0d1p",0x6810 },
+ { "cciss/c0d2p",0x6820 },
+ { "cciss/c0d3p",0x6830 },
+ { "cciss/c0d4p",0x6840 },
+ { "cciss/c0d5p",0x6850 },
+ { "cciss/c0d6p",0x6860 },
+ { "cciss/c0d7p",0x6870 },
+ { "cciss/c0d8p",0x6880 },
+ { "cciss/c0d9p",0x6890 },
+ { "cciss/c0d10p",0x68A0 },
+ { "cciss/c0d11p",0x68B0 },
+ { "cciss/c0d12p",0x68C0 },
+ { "cciss/c0d13p",0x68D0 },
+ { "cciss/c0d14p",0x68E0 },
+ { "cciss/c0d15p",0x68F0 },
+ { "cciss/c1d0p",0x6900 },
+ { "cciss/c2d0p",0x6A00 },
+ { "cciss/c3d0p",0x6B00 },
+ { "cciss/c4d0p",0x6C00 },
+ { "cciss/c5d0p",0x6D00 },
+ { "cciss/c6d0p",0x6E00 },
+ { "cciss/c7d0p",0x6F00 },
+ { "ataraid/d0p",0x7200 },
+ { "ataraid/d1p",0x7210 },
+ { "ataraid/d2p",0x7220 },
+ { "ataraid/d3p",0x7230 },
+ { "ataraid/d4p",0x7240 },
+ { "ataraid/d5p",0x7250 },
+ { "ataraid/d6p",0x7260 },
+ { "ataraid/d7p",0x7270 },
+ { "ataraid/d8p",0x7280 },
+ { "ataraid/d9p",0x7290 },
+ { "ataraid/d10p",0x72A0 },
+ { "ataraid/d11p",0x72B0 },
+ { "ataraid/d12p",0x72C0 },
+ { "ataraid/d13p",0x72D0 },
+ { "ataraid/d14p",0x72E0 },
+ { "ataraid/d15p",0x72F0 },
+ { "rd/c0d0p",0x3000 },
+ { "rd/c0d0p1",0x3001 },
+ { "rd/c0d0p2",0x3002 },
+ { "rd/c0d0p3",0x3003 },
+ { "rd/c0d0p4",0x3004 },
+ { "rd/c0d0p5",0x3005 },
+ { "rd/c0d0p6",0x3006 },
+ { "rd/c0d0p7",0x3007 },
+ { "rd/c0d0p8",0x3008 },
+ { "rd/c0d1p",0x3008 },
+ { "rd/c0d1p1",0x3009 },
+ { "rd/c0d1p2",0x300a },
+ { "rd/c0d1p3",0x300b },
+ { "rd/c0d1p4",0x300c },
+ { "rd/c0d1p5",0x300d },
+ { "rd/c0d1p6",0x300e },
+ { "rd/c0d1p7",0x300f },
+ { "rd/c0d1p8",0x3010 },
+ { "nftla", 0x5d00 },
+ { "nftlb", 0x5d10 },
+ { "nftlc", 0x5d20 },
+ { "nftld", 0x5d30 },
+ { "ftla", 0x2c00 },
+ { "ftlb", 0x2c08 },
+ { "ftlc", 0x2c10 },
+ { "ftld", 0x2c18 },
+ { "mtdblock", 0x1f00 },
+ { "nb", 0x2b00 },
+#if defined(CONFIG_XENOLINUX_BLOCK)
+ { "xvda", 0x7D00 }, { "xvdb", 0x7D10 },
+ { "xvdc", 0x7D20 }, { "xvdd", 0x7D30 },
+ { "xvde", 0x7D40 }, { "xvdf", 0x7D50 },
+ { "xvdg", 0x7D60 }, { "xvdh", 0x7D70 },
+ { "xvdi", 0x7D80 }, { "xvdj", 0x7D90 },
+ { "xvdk", 0x7DA0 }, { "xvdl", 0x7DB0 },
+ { "xvdm", 0x7DC0 }, { "xvdn", 0x7DD0 },
+ { "xvdo", 0x7DE0 }, { "xvdp", 0x7DF0 },
+#endif
+ { NULL, 0 }
+};
+
+kdev_t __init name_to_kdev_t(char *line)
+{
+ int base = 0, offs;
+ char *end;
+
+ if (strncmp(line,"/dev/",5) == 0) {
+ struct dev_name_struct *dev = root_dev_names;
+ line += 5;
+ do {
+ int len = strlen(dev->name);
+ if (strncmp(line,dev->name,len) == 0) {
+ line += len;
+ base = dev->num;
+ break;
+ }
+ dev++;
+ } while (dev->name);
+ }
+ offs = simple_strtoul(line, &end, base?10:16);
+ if (*end)
+ offs = 0;
+ return to_kdev_t(base + offs);
+}
+
+static int __init root_dev_setup(char *line)
+{
+ int i;
+ char ch;
+
+ ROOT_DEV = name_to_kdev_t(line);
+ memset (root_device_name, 0, sizeof root_device_name);
+ if (strncmp (line, "/dev/", 5) == 0) line += 5;
+ for (i = 0; i < sizeof root_device_name - 1; ++i)
+ {
+ ch = line[i];
+ if ( isspace (ch) || (ch == ',') || (ch == '\0') ) break;
+ root_device_name[i] = ch;
+ }
+ return 1;
+}
+
+__setup("root=", root_dev_setup);
+
+static char * __initdata root_mount_data;
+static int __init root_data_setup(char *str)
+{
+ root_mount_data = str;
+ return 1;
+}
+
+static char * __initdata root_fs_names;
+static int __init fs_names_setup(char *str)
+{
+ root_fs_names = str;
+ return 1;
+}
+
+__setup("rootflags=", root_data_setup);
+__setup("rootfstype=", fs_names_setup);
+
+static void __init get_fs_names(char *page)
+{
+ char *s = page;
+
+ if (root_fs_names) {
+ strcpy(page, root_fs_names);
+ while (*s++) {
+ if (s[-1] == ',')
+ s[-1] = '\0';
+ }
+ } else {
+ int len = get_filesystem_list(page);
+ char *p, *next;
+
+ page[len] = '\0';
+ for (p = page-1; p; p = next) {
+ next = strchr(++p, '\n');
+ if (*p++ != '\t')
+ continue;
+ while ((*s++ = *p++) != '\n')
+ ;
+ s[-1] = '\0';
+ }
+ }
+ *s = '\0';
+}
+static void __init mount_block_root(char *name, int flags)
+{
+ char *fs_names = __getname();
+ char *p;
+
+ get_fs_names(fs_names);
+retry:
+ for (p = fs_names; *p; p += strlen(p)+1) {
+ int err = sys_mount(name, "/root", p, flags, root_mount_data);
+ switch (err) {
+ case 0:
+ goto out;
+ case -EACCES:
+ flags |= MS_RDONLY;
+ goto retry;
+ case -EINVAL:
+ continue;
+ }
+ /*
+ * Allow the user to distinguish between failed open
+ * and bad superblock on root device.
+ */
+ printk ("VFS: Cannot open root device \"%s\" or %s\n",
+ root_device_name, kdevname (ROOT_DEV));
+ printk ("Please append a correct \"root=\" boot option\n");
+ panic("VFS: Unable to mount root fs on %s",
+ kdevname(ROOT_DEV));
+ }
+ panic("VFS: Unable to mount root fs on %s", kdevname(ROOT_DEV));
+out:
+ putname(fs_names);
+ sys_chdir("/root");
+ ROOT_DEV = current->fs->pwdmnt->mnt_sb->s_dev;
+ printk("VFS: Mounted root (%s filesystem)%s.\n",
+ current->fs->pwdmnt->mnt_sb->s_type->name,
+ (current->fs->pwdmnt->mnt_sb->s_flags & MS_RDONLY) ? " readonly" : "");
+}
+
+#ifdef CONFIG_ROOT_NFS
+static int __init mount_nfs_root(void)
+{
+ void *data = nfs_root_data();
+
+ if (data && sys_mount("/dev/root","/root","nfs",root_mountflags,data) == 0)
+ return 1;
+ return 0;
+}
+#endif
+
+static int __init create_dev(char *name, kdev_t dev, char *devfs_name)
+{
+ void *handle;
+ char path[64];
+ int n;
+
+ sys_unlink(name);
+ if (!do_devfs)
+ return sys_mknod(name, S_IFBLK|0600, kdev_t_to_nr(dev));
+
+ handle = devfs_find_handle(NULL, dev ? NULL : devfs_name,
+ MAJOR(dev), MINOR(dev), DEVFS_SPECIAL_BLK, 1);
+ if (!handle)
+ return -1;
+ n = devfs_generate_path(handle, path + 5, sizeof (path) - 5);
+ if (n < 0)
+ return -1;
+ return sys_symlink(path + n + 5, name);
+}
+
+#if defined(CONFIG_BLK_DEV_RAM) || defined(CONFIG_BLK_DEV_FD)
+static void __init change_floppy(char *fmt, ...)
+{
+ struct termios termios;
+ char buf[80];
+ char c;
+ int fd;
+ va_list args;
+ va_start(args, fmt);
+ vsprintf(buf, fmt, args);
+ va_end(args);
+ fd = open("/dev/root", O_RDWR | O_NDELAY, 0);
+ if (fd >= 0) {
+ sys_ioctl(fd, FDEJECT, 0);
+ close(fd);
+ }
+ printk(KERN_NOTICE "VFS: Insert %s and press ENTER\n", buf);
+ fd = open("/dev/console", O_RDWR, 0);
+ if (fd >= 0) {
+ sys_ioctl(fd, TCGETS, (long)&termios);
+ termios.c_lflag &= ~ICANON;
+ sys_ioctl(fd, TCSETSF, (long)&termios);
+ read(fd, &c, 1);
+ termios.c_lflag |= ICANON;
+ sys_ioctl(fd, TCSETSF, (long)&termios);
+ close(fd);
+ }
+}
+#endif
+
+#ifdef CONFIG_BLK_DEV_RAM
+
+int __initdata rd_prompt = 1; /* 1 = prompt for RAM disk, 0 = don't prompt */
+
+static int __init prompt_ramdisk(char *str)
+{
+ rd_prompt = simple_strtol(str,NULL,0) & 1;
+ return 1;
+}
+__setup("prompt_ramdisk=", prompt_ramdisk);
+
+int __initdata rd_image_start; /* starting block # of image */
+
+static int __init ramdisk_start_setup(char *str)
+{
+ rd_image_start = simple_strtol(str,NULL,0);
+ return 1;
+}
+__setup("ramdisk_start=", ramdisk_start_setup);
+
+static int __init crd_load(int in_fd, int out_fd);
+
+/*
+ * This routine tries to find a RAM disk image to load, and returns the
+ * number of blocks to read for a non-compressed image, 0 if the image
+ * is a compressed image, and -1 if an image with the right magic
+ * numbers could not be found.
+ *
+ * We currently check for the following magic numbers:
+ * minix
+ * ext2
+ * romfs
+ * gzip
+ */
+static int __init
+identify_ramdisk_image(int fd, int start_block)
+{
+ const int size = 512;
+ struct minix_super_block *minixsb;
+ struct ext2_super_block *ext2sb;
+ struct romfs_super_block *romfsb;
+ int nblocks = -1;
+ unsigned char *buf;
+
+ buf = kmalloc(size, GFP_KERNEL);
+ if (buf == 0)
+ return -1;
+
+ minixsb = (struct minix_super_block *) buf;
+ ext2sb = (struct ext2_super_block *) buf;
+ romfsb = (struct romfs_super_block *) buf;
+ memset(buf, 0xe5, size);
+
+ /*
+ * Read block 0 to test for gzipped kernel
+ */
+ lseek(fd, start_block * BLOCK_SIZE, 0);
+ read(fd, buf, size);
+
+ /*
+ * If it matches the gzip magic numbers, return -1
+ */
+ if (buf[0] == 037 && ((buf[1] == 0213) || (buf[1] == 0236))) {
+ printk(KERN_NOTICE
+ "RAMDISK: Compressed image found at block %d\n",
+ start_block);
+ nblocks = 0;
+ goto done;
+ }
+
+ /* romfs is at block zero too */
+ if (romfsb->word0 == ROMSB_WORD0 &&
+ romfsb->word1 == ROMSB_WORD1) {
+ printk(KERN_NOTICE
+ "RAMDISK: romfs filesystem found at block %d\n",
+ start_block);
+ nblocks = (ntohl(romfsb->size)+BLOCK_SIZE-1)>>BLOCK_SIZE_BITS;
+ goto done;
+ }
+
+ /*
+ * Read block 1 to test for minix and ext2 superblock
+ */
+ lseek(fd, (start_block+1) * BLOCK_SIZE, 0);
+ read(fd, buf, size);
+
+ /* Try minix */
+ if (minixsb->s_magic == MINIX_SUPER_MAGIC ||
+ minixsb->s_magic == MINIX_SUPER_MAGIC2) {
+ printk(KERN_NOTICE
+ "RAMDISK: Minix filesystem found at block %d\n",
+ start_block);
+ nblocks = minixsb->s_nzones << minixsb->s_log_zone_size;
+ goto done;
+ }
+
+ /* Try ext2 */
+ if (ext2sb->s_magic == cpu_to_le16(EXT2_SUPER_MAGIC)) {
+ printk(KERN_NOTICE
+ "RAMDISK: ext2 filesystem found at block %d\n",
+ start_block);
+ nblocks = le32_to_cpu(ext2sb->s_blocks_count);
+ goto done;
+ }
+
+ printk(KERN_NOTICE
+ "RAMDISK: Couldn't find valid RAM disk image starting at %d.\n",
+ start_block);
+
+done:
+ lseek(fd, start_block * BLOCK_SIZE, 0);
+ kfree(buf);
+ return nblocks;
+}
+#endif
+
+static int __init rd_load_image(char *from)
+{
+ int res = 0;
+
+#ifdef CONFIG_BLK_DEV_RAM
+ int in_fd, out_fd;
+ unsigned long rd_blocks, devblocks;
+ int nblocks, i;
+ char *buf;
+ unsigned short rotate = 0;
+#if !defined(CONFIG_ARCH_S390) && !defined(CONFIG_PPC_ISERIES)
+ char rotator[4] = { '|' , '/' , '-' , '\\' };
+#endif
+
+ out_fd = open("/dev/ram", O_RDWR, 0);
+ if (out_fd < 0)
+ goto out;
+
+ in_fd = open(from, O_RDONLY, 0);
+ if (in_fd < 0)
+ goto noclose_input;
+
+ nblocks = identify_ramdisk_image(in_fd, rd_image_start);
+ if (nblocks < 0)
+ goto done;
+
+ if (nblocks == 0) {
+#ifdef BUILD_CRAMDISK
+ if (crd_load(in_fd, out_fd) == 0)
+ goto successful_load;
+#else
+ printk(KERN_NOTICE
+ "RAMDISK: Kernel does not support compressed "
+ "RAM disk images\n");
+#endif
+ goto done;
+ }
+
+ /*
+ * NOTE NOTE: nblocks suppose that the blocksize is BLOCK_SIZE, so
+ * rd_load_image will work only with filesystem BLOCK_SIZE wide!
+ * So make sure to use 1k blocksize while generating ext2fs
+ * ramdisk-images.
+ */
+ if (sys_ioctl(out_fd, BLKGETSIZE, (unsigned long)&rd_blocks) < 0)
+ rd_blocks = 0;
+ else
+ rd_blocks >>= 1;
+
+ if (nblocks > rd_blocks) {
+ printk("RAMDISK: image too big! (%d/%lu blocks)\n",
+ nblocks, rd_blocks);
+ goto done;
+ }
+
+ /*
+ * OK, time to copy in the data
+ */
+ buf = kmalloc(BLOCK_SIZE, GFP_KERNEL);
+ if (buf == 0) {
+ printk(KERN_ERR "RAMDISK: could not allocate buffer\n");
+ goto done;
+ }
+
+ if (sys_ioctl(in_fd, BLKGETSIZE, (unsigned long)&devblocks) < 0)
+ devblocks = 0;
+ else
+ devblocks >>= 1;
+
+ if (strcmp(from, "/dev/initrd") == 0)
+ devblocks = nblocks;
+
+ if (devblocks == 0) {
+ printk(KERN_ERR "RAMDISK: could not determine device size\n");
+ goto done;
+ }
+
+ printk(KERN_NOTICE "RAMDISK: Loading %d blocks [%ld disk%s] into ram disk... ",
+ nblocks, ((nblocks-1)/devblocks)+1, nblocks>devblocks ? "s" : "");
+ for (i=0; i < nblocks; i++) {
+ if (i && (i % devblocks == 0)) {
+ printk("done disk #%ld.\n", i/devblocks);
+ rotate = 0;
+ if (close(in_fd)) {
+ printk("Error closing the disk.\n");
+ goto noclose_input;
+ }
+ change_floppy("disk #%d", i/devblocks+1);
+ in_fd = open(from, O_RDONLY, 0);
+ if (in_fd < 0) {
+ printk("Error opening disk.\n");
+ goto noclose_input;
+ }
+ printk("Loading disk #%ld... ", i/devblocks+1);
+ }
+ read(in_fd, buf, BLOCK_SIZE);
+ write(out_fd, buf, BLOCK_SIZE);
+#if !defined(CONFIG_ARCH_S390) && !defined(CONFIG_PPC_ISERIES)
+ if (!(i % 16)) {
+ printk("%c\b", rotator[rotate & 0x3]);
+ rotate++;
+ }
+#endif
+ }
+ printk("done.\n");
+ kfree(buf);
+
+successful_load:
+ res = 1;
+done:
+ close(in_fd);
+noclose_input:
+ close(out_fd);
+out:
+ sys_unlink("/dev/ram");
+#endif
+ return res;
+}
+
+static int __init rd_load_disk(int n)
+{
+#ifdef CONFIG_BLK_DEV_RAM
+ if (rd_prompt)
+ change_floppy("root floppy disk to be loaded into RAM disk");
+ create_dev("/dev/ram", MKDEV(RAMDISK_MAJOR, n), NULL);
+#endif
+ return rd_load_image("/dev/root");
+}
+
+#ifdef CONFIG_DEVFS_FS
+
+static void __init convert_name(char *prefix, char *name, char *p, int part)
+{
+ int host, bus, target, lun;
+ char dest[64];
+ char src[64];
+ char *base = p - 1;
+
+ /* Decode "c#b#t#u#" */
+ if (*p++ != 'c')
+ return;
+ host = simple_strtol(p, &p, 10);
+ if (*p++ != 'b')
+ return;
+ bus = simple_strtol(p, &p, 10);
+ if (*p++ != 't')
+ return;
+ target = simple_strtol(p, &p, 10);
+ if (*p++ != 'u')
+ return;
+ lun = simple_strtol(p, &p, 10);
+ if (!part)
+ sprintf(dest, "%s/host%d/bus%d/target%d/lun%d",
+ prefix, host, bus, target, lun);
+ else if (*p++ == 'p')
+ sprintf(dest, "%s/host%d/bus%d/target%d/lun%d/part%s",
+ prefix, host, bus, target, lun, p);
+ else
+ sprintf(dest, "%s/host%d/bus%d/target%d/lun%d/disc",
+ prefix, host, bus, target, lun);
+ *base = '\0';
+ sprintf(src, "/dev/%s", name);
+ sys_mkdir(src, 0755);
+ *base = '/';
+ sprintf(src, "/dev/%s", name);
+ sys_symlink(dest, src);
+}
+
+static void __init devfs_make_root(char *name)
+{
+
+ if (!strncmp(name, "sd/", 3))
+ convert_name("../scsi", name, name+3, 1);
+ else if (!strncmp(name, "sr/", 3))
+ convert_name("../scsi", name, name+3, 0);
+ else if (!strncmp(name, "ide/hd/", 7))
+ convert_name("..", name, name + 7, 1);
+ else if (!strncmp(name, "ide/cd/", 7))
+ convert_name("..", name, name + 7, 0);
+}
+#else
+static void __init devfs_make_root(char *name)
+{
+}
+#endif
+
+static void __init mount_root(void)
+{
+#ifdef CONFIG_ROOT_NFS
+ if (MAJOR(ROOT_DEV) == UNNAMED_MAJOR) {
+ if (mount_nfs_root()) {
+ sys_chdir("/root");
+ ROOT_DEV = current->fs->pwdmnt->mnt_sb->s_dev;
+ printk("VFS: Mounted root (nfs filesystem).\n");
+ return;
+ }
+ printk(KERN_ERR "VFS: Unable to mount root fs via NFS, trying floppy.\n");
+ ROOT_DEV = MKDEV(FLOPPY_MAJOR, 0);
+ }
+#endif
+printk("root_device_name = %s\n",root_device_name);
+ devfs_make_root(root_device_name);
+ create_dev("/dev/root", ROOT_DEV, root_device_name);
+#ifdef CONFIG_BLK_DEV_FD
+ if (MAJOR(ROOT_DEV) == FLOPPY_MAJOR) {
+ /* rd_doload is 2 for a dual initrd/ramload setup */
+ if (rd_doload==2) {
+ if (rd_load_disk(1)) {
+ ROOT_DEV = MKDEV(RAMDISK_MAJOR, 1);
+ create_dev("/dev/root", ROOT_DEV, NULL);
+ }
+ } else
+ change_floppy("root floppy");
+ }
+#endif
+ mount_block_root("/dev/root", root_mountflags);
+}
+
+#ifdef CONFIG_BLK_DEV_INITRD
+static int old_fd, root_fd;
+static int do_linuxrc(void * shell)
+{
+ static char *argv[] = { "linuxrc", NULL, };
+ extern char * envp_init[];
+
+ close(old_fd);
+ close(root_fd);
+ close(0);
+ close(1);
+ close(2);
+ setsid();
+ (void) open("/dev/console",O_RDWR,0);
+ (void) dup(0);
+ (void) dup(0);
+ return execve(shell, argv, envp_init);
+}
+
+#endif
+
+static void __init handle_initrd(void)
+{
+#ifdef CONFIG_BLK_DEV_INITRD
+ int ram0 = kdev_t_to_nr(MKDEV(RAMDISK_MAJOR,0));
+ int error;
+ int i, pid;
+
+ create_dev("/dev/root.old", ram0, NULL);
+ /* mount initrd on rootfs' /root */
+ mount_block_root("/dev/root.old", root_mountflags & ~MS_RDONLY);
+ sys_mkdir("/old", 0700);
+ root_fd = open("/", 0, 0);
+ old_fd = open("/old", 0, 0);
+ /* move initrd over / and chdir/chroot in initrd root */
+ sys_chdir("/root");
+ sys_mount(".", "/", NULL, MS_MOVE, NULL);
+ sys_chroot(".");
+ mount_devfs_fs ();
+
+ pid = kernel_thread(do_linuxrc, "/linuxrc", SIGCHLD);
+ if (pid > 0) {
+ while (pid != wait(&i))
+ yield();
+ }
+
+ /* move initrd to rootfs' /old */
+ sys_fchdir(old_fd);
+ sys_mount("/", ".", NULL, MS_MOVE, NULL);
+ /* switch root and cwd back to / of rootfs */
+ sys_fchdir(root_fd);
+ sys_chroot(".");
+ sys_umount("/old/dev", 0);
+ close(old_fd);
+ close(root_fd);
+
+ if (real_root_dev == ram0) {
+ sys_chdir("/old");
+ return;
+ }
+
+ ROOT_DEV = real_root_dev;
+ mount_root();
+
+ printk(KERN_NOTICE "Trying to move old root to /initrd ... ");
+ error = sys_mount("/old", "/root/initrd", NULL, MS_MOVE, NULL);
+ if (!error)
+ printk("okay\n");
+ else {
+ int fd = open("/dev/root.old", O_RDWR, 0);
+ printk("failed\n");
+ printk(KERN_NOTICE "Unmounting old root\n");
+ sys_umount("/old", MNT_DETACH);
+ printk(KERN_NOTICE "Trying to free ramdisk memory ... ");
+ if (fd < 0) {
+ error = fd;
+ } else {
+ error = sys_ioctl(fd, BLKFLSBUF, 0);
+ close(fd);
+ }
+ printk(!error ? "okay\n" : "failed\n");
+ }
+#endif
+}
+
+static int __init initrd_load(void)
+{
+#ifdef CONFIG_BLK_DEV_INITRD
+ create_dev("/dev/ram", MKDEV(RAMDISK_MAJOR, 0), NULL);
+ create_dev("/dev/initrd", MKDEV(RAMDISK_MAJOR, INITRD_MINOR), NULL);
+#endif
+ return rd_load_image("/dev/initrd");
+}
+
+/*
+ * Prepare the namespace - decide what/where to mount, load ramdisks, etc.
+ */
+void prepare_namespace(void)
+{
+ int is_floppy = MAJOR(ROOT_DEV) == FLOPPY_MAJOR;
+#ifdef CONFIG_ALL_PPC
+ extern void arch_discover_root(void);
+ arch_discover_root();
+#endif /* CONFIG_ALL_PPC */
+#ifdef CONFIG_BLK_DEV_INITRD
+ if (!initrd_start)
+ mount_initrd = 0;
+ real_root_dev = ROOT_DEV;
+#endif
+ sys_mkdir("/dev", 0700);
+ sys_mkdir("/root", 0700);
+ sys_mknod("/dev/console", S_IFCHR|0600, MKDEV(TTYAUX_MAJOR, 1));
+#ifdef CONFIG_DEVFS_FS
+ sys_mount("devfs", "/dev", "devfs", 0, NULL);
+ do_devfs = 1;
+#endif
+
+ create_dev("/dev/root", ROOT_DEV, NULL);
+ if (mount_initrd) {
+ if (initrd_load() && ROOT_DEV != MKDEV(RAMDISK_MAJOR, 0)) {
+ handle_initrd();
+ goto out;
+ }
+ } else if (is_floppy && rd_doload && rd_load_disk(0))
+ ROOT_DEV = MKDEV(RAMDISK_MAJOR, 0);
+ mount_root();
+out:
+ sys_umount("/dev", 0);
+ sys_mount(".", "/", NULL, MS_MOVE, NULL);
+ sys_chroot(".");
+ mount_devfs_fs ();
+}
+
+#if defined(BUILD_CRAMDISK) && defined(CONFIG_BLK_DEV_RAM)
+
+/*
+ * gzip declarations
+ */
+
+#define OF(args) args
+
+#ifndef memzero
+#define memzero(s, n) memset ((s), 0, (n))
+#endif
+
+typedef unsigned char uch;
+typedef unsigned short ush;
+typedef unsigned long ulg;
+
+#define INBUFSIZ 4096
+#define WSIZE 0x8000 /* window size--must be a power of two, and */
+ /* at least 32K for zip's deflate method */
+
+static uch *inbuf;
+static uch *window;
+
+static unsigned insize; /* valid bytes in inbuf */
+static unsigned inptr; /* index of next byte to be processed in inbuf */
+static unsigned outcnt; /* bytes in output buffer */
+static int exit_code;
+static long bytes_out;
+static int crd_infd, crd_outfd;
+
+#define get_byte() (inptr < insize ? inbuf[inptr++] : fill_inbuf())
+
+/* Diagnostic functions (stubbed out) */
+#define Assert(cond,msg)
+#define Trace(x)
+#define Tracev(x)
+#define Tracevv(x)
+#define Tracec(c,x)
+#define Tracecv(c,x)
+
+#define STATIC static
+
+static int fill_inbuf(void);
+static void flush_window(void);
+static void *malloc(int size);
+static void free(void *where);
+static void error(char *m);
+static void gzip_mark(void **);
+static void gzip_release(void **);
+
+#include "../lib/inflate.c"
+
+static void __init *malloc(int size)
+{
+ return kmalloc(size, GFP_KERNEL);
+}
+
+static void __init free(void *where)
+{
+ kfree(where);
+}
+
+static void __init gzip_mark(void **ptr)
+{
+}
+
+static void __init gzip_release(void **ptr)
+{
+}
+
+
+/* ===========================================================================
+ * Fill the input buffer. This is called only when the buffer is empty
+ * and at least one byte is really needed.
+ */
+static int __init fill_inbuf(void)
+{
+ if (exit_code) return -1;
+
+ insize = read(crd_infd, inbuf, INBUFSIZ);
+ if (insize == 0) return -1;
+
+ inptr = 1;
+
+ return inbuf[0];
+}
+
+/* ===========================================================================
+ * Write the output window window[0..outcnt-1] and update crc and bytes_out.
+ * (Used for the decompressed data only.)
+ */
+static void __init flush_window(void)
+{
+ ulg c = crc; /* temporary variable */
+ unsigned n;
+ uch *in, ch;
+
+ write(crd_outfd, window, outcnt);
+ in = window;
+ for (n = 0; n < outcnt; n++) {
+ ch = *in++;
+ c = crc_32_tab[((int)c ^ ch) & 0xff] ^ (c >> 8);
+ }
+ crc = c;
+ bytes_out += (ulg)outcnt;
+ outcnt = 0;
+}
+
+static void __init error(char *x)
+{
+ printk(KERN_ERR "%s", x);
+ exit_code = 1;
+}
+
+static int __init crd_load(int in_fd, int out_fd)
+{
+ int result;
+
+ insize = 0; /* valid bytes in inbuf */
+ inptr = 0; /* index of next byte to be processed in inbuf */
+ outcnt = 0; /* bytes in output buffer */
+ exit_code = 0;
+ bytes_out = 0;
+ crc = (ulg)0xffffffffL; /* shift register contents */
+
+ crd_infd = in_fd;
+ crd_outfd = out_fd;
+ inbuf = kmalloc(INBUFSIZ, GFP_KERNEL);
+ if (inbuf == 0) {
+ printk(KERN_ERR "RAMDISK: Couldn't allocate gzip buffer\n");
+ return -1;
+ }
+ window = kmalloc(WSIZE, GFP_KERNEL);
+ if (window == 0) {
+ printk(KERN_ERR "RAMDISK: Couldn't allocate gzip window\n");
+ kfree(inbuf);
+ return -1;
+ }
+ makecrc();
+ result = gunzip();
+ kfree(inbuf);
+ kfree(window);
+ return result;
+}
+
+#endif /* BUILD_CRAMDISK && CONFIG_BLK_DEV_RAM */
--- /dev/null
+/*
+ * linux/kernel/panic.c
+ *
+ * Copyright (C) 1991, 1992 Linus Torvalds
+ */
+
+/*
+ * This function is used through-out the kernel (including mm and fs)
+ * to indicate a major problem.
+ */
+#include <linux/config.h>
+#include <linux/sched.h>
+#include <linux/delay.h>
+#include <linux/reboot.h>
+#include <linux/notifier.h>
+#include <linux/init.h>
+#include <linux/sysrq.h>
+#include <linux/interrupt.h>
+
+asmlinkage void sys_sync(void); /* it's really int */
+
+int panic_timeout;
+
+struct notifier_block *panic_notifier_list;
+
+static int __init panic_setup(char *str)
+{
+ panic_timeout = simple_strtoul(str, NULL, 0);
+ return 1;
+}
+
+__setup("panic=", panic_setup);
+
+/**
+ * panic - halt the system
+ * @fmt: The text string to print
+ *
+ * Display a message, then perform cleanups. Functions in the panic
+ * notifier list are called after the filesystem cache is flushed (when possible).
+ *
+ * This function never returns.
+ */
+
+NORET_TYPE void panic(const char * fmt, ...)
+{
+ static char buf[1024];
+ va_list args;
+#if defined(CONFIG_ARCH_S390)
+ unsigned long caller = (unsigned long) __builtin_return_address(0);
+#endif
+
+ bust_spinlocks(1);
+ va_start(args, fmt);
+ vsprintf(buf, fmt, args);
+ va_end(args);
+ printk(KERN_EMERG "Kernel panic: %s\n",buf);
+ if (in_interrupt())
+ printk(KERN_EMERG "In interrupt handler - not syncing\n");
+ else if (!current->pid)
+ printk(KERN_EMERG "In idle task - not syncing\n");
+ else
+ sys_sync();
+ bust_spinlocks(0);
+
+#ifdef CONFIG_SMP
+ smp_send_stop();
+#endif
+
+ notifier_call_chain(&panic_notifier_list, 0, NULL);
+
+ if (panic_timeout > 0)
+ {
+ /*
+ * Delay timeout seconds before rebooting the machine.
+ * We can't use the "normal" timers since we just panicked..
+ */
+ printk(KERN_EMERG "Rebooting in %d seconds..",panic_timeout);
+ mdelay(panic_timeout*1000);
+ /*
+ * Should we run the reboot notifier. For the moment Im
+ * choosing not too. It might crash, be corrupt or do
+ * more harm than good for other reasons.
+ */
+ machine_restart(NULL);
+ }
+#ifdef __sparc__
+ {
+ extern int stop_a_enabled;
+ /* Make sure the user can actually press L1-A */
+ stop_a_enabled = 1;
+ printk("Press L1-A to return to the boot prom\n");
+ }
+#endif
+#if defined(CONFIG_ARCH_S390)
+ disabled_wait(caller);
+#endif
+ sti();
+ for(;;) {
+#if defined(CONFIG_X86) && defined(CONFIG_VT)
+ extern void panic_blink(void);
+ panic_blink();
+#endif
+ CHECK_EMERGENCY_SYNC
+#if defined(CONFIG_XENO)
+ HYPERVISOR_exit();
+#endif
+ }
+}
+
+/**
+ * print_tainted - return a string to represent the kernel taint state.
+ *
+ * The string is overwritten by the next call to print_taint().
+ */
+
+const char *print_tainted()
+{
+ static char buf[20];
+ if (tainted) {
+ snprintf(buf, sizeof(buf), "Tainted: %c%c",
+ tainted & 1 ? 'P' : 'G',
+ tainted & 2 ? 'F' : ' ');
+ }
+ else
+ snprintf(buf, sizeof(buf), "Not tainted");
+ return(buf);
+}
+
+int tainted = 0;
+
+/*
+ * A BUG() call in an inline function in a header should be avoided,
+ * because it can seriously bloat the kernel. So here we have
+ * helper functions.
+ * We lose the BUG()-time file-and-line info this way, but it's
+ * usually not very useful from an inline anyway. The backtrace
+ * tells us what we want to know.
+ */
+
+void __out_of_line_bug(int line)
+{
+ printk("kernel BUG in header file at line %d\n", line);
+
+ BUG();
+
+ /* Satisfy __attribute__((noreturn)) */
+ for ( ; ; )
+ ;
+}
--- /dev/null
+#!/bin/sh
+
+# mkbuildtree <build tree>
+#
+# Creates symbolic links in <build tree> for the sparse tree
+# in the current directory.
+
+# Script to determine the relative path between two directories.
+# Copyright (c) D. J. Hawkey Jr. 2002
+# Fixed for Xen project by K. Fraser in 2003.
+abs_to_rel ()
+{
+ local CWD SRCPATH
+
+ if [ "$1" != "/" -a "${1##*[^/]}" = "/" ]; then
+ SRCPATH=${1%?}
+ else
+ SRCPATH=$1
+ fi
+ if [ "$2" != "/" -a "${2##*[^/]}" = "/" ]; then
+ DESTPATH=${2%?}
+ else
+ DESTPATH=$2
+ fi
+
+ CWD=$PWD
+ [ "${1%%[^/]*}" != "/" ] && cd $1 && SRCPATH=$PWD
+ [ "${2%%[^/]*}" != "/" ] && cd $2 && DESTPATH=$PWD
+ [ "$CWD" != "$PWD" ] && cd $CWD
+
+ BASEPATH=$SRCPATH
+
+ [ "$SRCPATH" = "$DESTPATH" ] && DESTPATH="." && return
+ [ "$SRCPATH" = "/" ] && DESTPATH=${DESTPATH#?} && return
+
+ while [ "$BASEPATH/" != "${DESTPATH%${DESTPATH#$BASEPATH/}}" ]; do
+ BASEPATH=${BASEPATH%/*}
+ done
+
+ SRCPATH=${SRCPATH#$BASEPATH}
+ DESTPATH=${DESTPATH#$BASEPATH}
+ DESTPATH=${DESTPATH#?}
+ while [ -n "$SRCPATH" ]; do
+ SRCPATH=${SRCPATH%/*}
+ DESTPATH="../$DESTPATH"
+ done
+
+ [ -z "$BASEPATH" ] && BASEPATH="/"
+ [ "${DESTPATH##*[^/]}" = "/" ] && DESTPATH=${DESTPATH%?}
+}
+
+
+[ "$1" == "" ] && { echo "Syntax: $0 <linux tree to xenify>"; exit 1; }
+
+# Get absolute path to the destination directory
+pushd . >/dev/null
+cd ${1}
+AD=`pwd`
+popd >/dev/null
+
+# Get absolute path to the source directory
+AS=`pwd`
+
+# Get path to source, relative to destination
+abs_to_rel ${AD} ${AS}
+RS=$DESTPATH
+
+# Remove old copies of files and directories at the destination
+for i in `find . -type f -o -type l` ; do rm -f ${AD}/${i#./} ; done
+
+# We now work from the destination directory
+cd ${AD}
+
+# Create symlinks of files and directories which exist in the sparse source
+${AS}/lndir-rel -silent ${RS}
+rm -f mkbuildtree lndir-rel
+
+## There are a whole bunch of special symlinks, mostly for files
+## which are identical in the i386 and xeno-i386 architecture-dependent
+## subdirectories.
+
+# This first symlink is special: it links to shared files in Xen's source tree
+rm -rf ${AD}/include/asm-xeno/hypervisor-ifs
+mkdir ${AD}/include/asm-xeno/hypervisor-ifs
+cd ${AD}/include/asm-xeno/hypervisor-ifs
+${AS}/lndir-rel -silent ../../../${RS}/../xen/include/hypervisor-ifs
+
+# The remainder are the i386 -> xeno-i386 links
+cd ..
+ln -sf ../asm-i386/a.out.h
+ln -sf ../asm-i386/apicdef.h
+ln -sf ../asm-i386/apic.h
+ln -sf ../asm-i386/atomic.h
+ln -sf ../asm-i386/bitops.h
+ln -sf ../asm-i386/boot.h
+ln -sf ../asm-i386/byteorder.h
+ln -sf ../asm-i386/cache.h
+ln -sf ../asm-i386/checksum.h
+ln -sf ../asm-i386/cpufeature.h
+ln -sf ../asm-i386/current.h
+ln -sf ../asm-i386/debugreg.h
+ln -sf ../asm-i386/delay.h
+ln -sf ../asm-i386/div64.h
+ln -sf ../asm-i386/dma.h
+ln -sf ../asm-i386/elf.h
+ln -sf ../asm-i386/errno.h
+ln -sf ../asm-i386/fcntl.h
+ln -sf ../asm-i386/floppy.h
+ln -sf ../asm-i386/hardirq.h
+ln -sf ../asm-i386/hdreg.h
+ln -sf ../asm-i386/i387.h
+ln -sf ../asm-i386/ide.h
+ln -sf ../asm-i386/init.h
+ln -sf ../asm-i386/io_apic.h
+ln -sf ../asm-i386/ioctl.h
+ln -sf ../asm-i386/ioctls.h
+ln -sf ../asm-i386/ipcbuf.h
+ln -sf ../asm-i386/ipc.h
+ln -sf ../asm-i386/kmap_types.h
+ln -sf ../asm-i386/ldt.h
+ln -sf ../asm-i386/linux_logo.h
+ln -sf ../asm-i386/locks.h
+ln -sf ../asm-i386/math_emu.h
+ln -sf ../asm-i386/mc146818rtc.h
+ln -sf ../asm-i386/mca_dma.h
+ln -sf ../asm-i386/mman.h
+ln -sf ../asm-i386/mmx.h
+ln -sf ../asm-i386/module.h
+ln -sf ../asm-i386/mpspec.h
+ln -sf ../asm-i386/msgbuf.h
+ln -sf ../asm-i386/msr.h
+ln -sf ../asm-i386/mtrr.h
+ln -sf ../asm-i386/namei.h
+ln -sf ../asm-i386/param.h
+ln -sf ../asm-i386/parport.h
+ln -sf ../asm-i386/pgtable-3level.h
+ln -sf ../asm-i386/poll.h
+ln -sf ../asm-i386/posix_types.h
+ln -sf ../asm-i386/resource.h
+ln -sf ../asm-i386/rwlock.h
+ln -sf ../asm-i386/rwsem.h
+ln -sf ../asm-i386/scatterlist.h
+ln -sf ../asm-i386/semaphore.h
+ln -sf ../asm-i386/sembuf.h
+ln -sf ../asm-i386/serial.h
+ln -sf ../asm-i386/setup.h
+ln -sf ../asm-i386/shmbuf.h
+ln -sf ../asm-i386/shmparam.h
+ln -sf ../asm-i386/sigcontext.h
+ln -sf ../asm-i386/siginfo.h
+ln -sf ../asm-i386/signal.h
+ln -sf ../asm-i386/smplock.h
+ln -sf ../asm-i386/socket.h
+ln -sf ../asm-i386/sockios.h
+ln -sf ../asm-i386/softirq.h
+ln -sf ../asm-i386/spinlock.h
+ln -sf ../asm-i386/statfs.h
+ln -sf ../asm-i386/stat.h
+ln -sf ../asm-i386/string-486.h
+ln -sf ../asm-i386/string.h
+ln -sf ../asm-i386/termbits.h
+ln -sf ../asm-i386/termios.h
+ln -sf ../asm-i386/timex.h
+ln -sf ../asm-i386/tlb.h
+ln -sf ../asm-i386/types.h
+ln -sf ../asm-i386/uaccess.h
+ln -sf ../asm-i386/ucontext.h
+ln -sf ../asm-i386/unaligned.h
+ln -sf ../asm-i386/unistd.h
+ln -sf ../asm-i386/user.h
+ln -sf ../asm-i386/vga.h
+ln -sf ../asm-i386/xor.h
+
+cd ../../arch/xeno/kernel
+ln -sf ../../i386/kernel/i387.c
+ln -sf ../../i386/kernel/init_task.c
+ln -sf ../../i386/kernel/ptrace.c
+ln -sf ../../i386/kernel/semaphore.c
+ln -sf ../../i386/kernel/sys_i386.c
+cd ../lib
+ln -sf ../../i386/lib/checksum.S
+ln -sf ../../i386/lib/dec_and_lock.c
+ln -sf ../../i386/lib/getuser.S
+ln -sf ../../i386/lib/iodebug.c
+ln -sf ../../i386/lib/memcpy.c
+ln -sf ../../i386/lib/mmx.c
+ln -sf ../../i386/lib/old-checksum.c
+ln -sf ../../i386/lib/strstr.c
+ln -sf ../../i386/lib/usercopy.c
+cd ../mm
+ln -sf ../../i386/mm/extable.c
+ln -sf ../../i386/mm/pageattr.c
--- /dev/null
+/*
+ * linux/mm/memory.c
+ *
+ * Copyright (C) 1991, 1992, 1993, 1994 Linus Torvalds
+ */
+
+/*
+ * demand-loading started 01.12.91 - seems it is high on the list of
+ * things wanted, and it should be easy to implement. - Linus
+ */
+
+/*
+ * Ok, demand-loading was easy, shared pages a little bit tricker. Shared
+ * pages started 02.12.91, seems to work. - Linus.
+ *
+ * Tested sharing by executing about 30 /bin/sh: under the old kernel it
+ * would have taken more than the 6M I have free, but it worked well as
+ * far as I could see.
+ *
+ * Also corrected some "invalidate()"s - I wasn't doing enough of them.
+ */
+
+/*
+ * Real VM (paging to/from disk) started 18.12.91. Much more work and
+ * thought has to go into this. Oh, well..
+ * 19.12.91 - works, somewhat. Sometimes I get faults, don't know why.
+ * Found it. Everything seems to work now.
+ * 20.12.91 - Ok, making the swap-device changeable like the root.
+ */
+
+/*
+ * 05.04.94 - Multi-page memory management added for v1.1.
+ * Idea by Alex Bligh (alex@cconcepts.co.uk)
+ *
+ * 16.07.99 - Support of BIGMEM added by Gerhard Wichert, Siemens AG
+ * (Gerhard.Wichert@pdb.siemens.de)
+ */
+
+#include <linux/mm.h>
+#include <linux/mman.h>
+#include <linux/swap.h>
+#include <linux/smp_lock.h>
+#include <linux/swapctl.h>
+#include <linux/iobuf.h>
+#include <linux/highmem.h>
+#include <linux/pagemap.h>
+#include <linux/module.h>
+
+#include <asm/pgalloc.h>
+#include <asm/uaccess.h>
+#include <asm/tlb.h>
+
+unsigned long max_mapnr;
+unsigned long num_physpages;
+unsigned long num_mappedpages;
+void * high_memory;
+struct page *highmem_start_page;
+
+/*
+ * We special-case the C-O-W ZERO_PAGE, because it's such
+ * a common occurrence (no need to read the page to know
+ * that it's zero - better for the cache and memory subsystem).
+ */
+static inline void copy_cow_page(struct page * from, struct page * to, unsigned long address)
+{
+ if (from == ZERO_PAGE(address)) {
+ clear_user_highpage(to, address);
+ return;
+ }
+ copy_user_highpage(to, from, address);
+}
+
+mem_map_t * mem_map;
+
+/*
+ * Called by TLB shootdown
+ */
+void __free_pte(pte_t pte)
+{
+ struct page *page = pte_page(pte);
+ if ((!VALID_PAGE(page)) || PageReserved(page))
+ return;
+ if (pte_dirty(pte))
+ set_page_dirty(page);
+ free_page_and_swap_cache(page);
+}
+
+
+/*
+ * Note: this doesn't free the actual pages themselves. That
+ * has been handled earlier when unmapping all the memory regions.
+ */
+static inline void free_one_pmd(pmd_t * dir)
+{
+ pte_t * pte;
+
+ if (pmd_none(*dir))
+ return;
+ if (pmd_bad(*dir)) {
+ pmd_ERROR(*dir);
+ pmd_clear(dir);
+ return;
+ }
+ pte = pte_offset(dir, 0);
+ pmd_clear(dir);
+ pte_free(pte);
+}
+
+static inline void free_one_pgd(pgd_t * dir)
+{
+ int j;
+ pmd_t * pmd;
+
+ if (pgd_none(*dir))
+ return;
+ if (pgd_bad(*dir)) {
+ pgd_ERROR(*dir);
+ pgd_clear(dir);
+ return;
+ }
+ pmd = pmd_offset(dir, 0);
+ pgd_clear(dir);
+ for (j = 0; j < PTRS_PER_PMD ; j++) {
+ prefetchw(pmd+j+(PREFETCH_STRIDE/16));
+ free_one_pmd(pmd+j);
+ }
+ pmd_free(pmd);
+}
+
+/* Low and high watermarks for page table cache.
+ The system should try to have pgt_water[0] <= cache elements <= pgt_water[1]
+ */
+int pgt_cache_water[2] = { 25, 50 };
+
+/* Returns the number of pages freed */
+int check_pgt_cache(void)
+{
+ return do_check_pgt_cache(pgt_cache_water[0], pgt_cache_water[1]);
+}
+
+
+/*
+ * This function clears all user-level page tables of a process - this
+ * is needed by execve(), so that old pages aren't in the way.
+ */
+void clear_page_tables(struct mm_struct *mm, unsigned long first, int nr)
+{
+ pgd_t * page_dir = mm->pgd;
+
+ spin_lock(&mm->page_table_lock);
+ page_dir += first;
+ do {
+ free_one_pgd(page_dir);
+ page_dir++;
+ } while (--nr);
+ XENO_flush_page_update_queue();
+ spin_unlock(&mm->page_table_lock);
+
+ /* keep the page table cache within bounds */
+ check_pgt_cache();
+}
+
+#define PTE_TABLE_MASK ((PTRS_PER_PTE-1) * sizeof(pte_t))
+#define PMD_TABLE_MASK ((PTRS_PER_PMD-1) * sizeof(pmd_t))
+
+/*
+ * copy one vm_area from one task to the other. Assumes the page tables
+ * already present in the new task to be cleared in the whole range
+ * covered by this vma.
+ *
+ * 08Jan98 Merged into one routine from several inline routines to reduce
+ * variable count and make things faster. -jj
+ *
+ * dst->page_table_lock is held on entry and exit,
+ * but may be dropped within pmd_alloc() and pte_alloc().
+ */
+int copy_page_range(struct mm_struct *dst, struct mm_struct *src,
+ struct vm_area_struct *vma)
+{
+ pgd_t * src_pgd, * dst_pgd;
+ unsigned long address = vma->vm_start;
+ unsigned long end = vma->vm_end;
+ unsigned long cow = (vma->vm_flags & (VM_SHARED | VM_MAYWRITE)) == VM_MAYWRITE;
+
+ src_pgd = pgd_offset(src, address)-1;
+ dst_pgd = pgd_offset(dst, address)-1;
+
+ for (;;) {
+ pmd_t * src_pmd, * dst_pmd;
+
+ src_pgd++; dst_pgd++;
+
+ /* copy_pmd_range */
+
+ if (pgd_none(*src_pgd))
+ goto skip_copy_pmd_range;
+ if (pgd_bad(*src_pgd)) {
+ pgd_ERROR(*src_pgd);
+ pgd_clear(src_pgd);
+skip_copy_pmd_range: address = (address + PGDIR_SIZE) & PGDIR_MASK;
+ if (!address || (address >= end))
+ goto out;
+ continue;
+ }
+
+ src_pmd = pmd_offset(src_pgd, address);
+ dst_pmd = pmd_alloc(dst, dst_pgd, address);
+ if (!dst_pmd)
+ goto nomem;
+
+ do {
+ pte_t * src_pte, * dst_pte;
+
+ /* copy_pte_range */
+
+ if (pmd_none(*src_pmd))
+ goto skip_copy_pte_range;
+ if (pmd_bad(*src_pmd)) {
+ pmd_ERROR(*src_pmd);
+ pmd_clear(src_pmd);
+skip_copy_pte_range: address = (address + PMD_SIZE) & PMD_MASK;
+ if (address >= end)
+ goto out;
+ goto cont_copy_pmd_range;
+ }
+
+ src_pte = pte_offset(src_pmd, address);
+ dst_pte = pte_alloc(dst, dst_pmd, address);
+ if (!dst_pte)
+ goto nomem;
+
+ spin_lock(&src->page_table_lock);
+ do {
+ pte_t pte = *src_pte;
+ struct page *ptepage;
+
+ /* copy_one_pte */
+
+ if (pte_none(pte))
+ goto cont_copy_pte_range_noset;
+ if (!pte_present(pte)) {
+ swap_duplicate(pte_to_swp_entry(pte));
+ goto cont_copy_pte_range;
+ }
+ ptepage = pte_page(pte);
+ if ((!VALID_PAGE(ptepage)) ||
+ PageReserved(ptepage))
+ goto cont_copy_pte_range;
+
+ /* If it's a COW mapping, write protect it both in the parent and the child */
+ if (cow && pte_write(pte)) {
+ /* XENO modification: modified ordering here to avoid RaW hazard. */
+ pte = *src_pte;
+ pte = pte_wrprotect(pte);
+ ptep_set_wrprotect(src_pte);
+ }
+
+ /* If it's a shared mapping, mark it clean in the child */
+ if (vma->vm_flags & VM_SHARED)
+ pte = pte_mkclean(pte);
+ pte = pte_mkold(pte);
+ get_page(ptepage);
+ dst->rss++;
+
+cont_copy_pte_range: set_pte(dst_pte, pte);
+cont_copy_pte_range_noset: address += PAGE_SIZE;
+ if (address >= end)
+ goto out_unlock;
+ src_pte++;
+ dst_pte++;
+ } while ((unsigned long)src_pte & PTE_TABLE_MASK);
+ spin_unlock(&src->page_table_lock);
+
+cont_copy_pmd_range: src_pmd++;
+ dst_pmd++;
+ } while ((unsigned long)src_pmd & PMD_TABLE_MASK);
+ }
+out_unlock:
+ spin_unlock(&src->page_table_lock);
+out:
+ return 0;
+nomem:
+ return -ENOMEM;
+}
+
+/*
+ * Return indicates whether a page was freed so caller can adjust rss
+ */
+static inline void forget_pte(pte_t page)
+{
+ if (!pte_none(page)) {
+ printk("forget_pte: old mapping existed!\n");
+ BUG();
+ }
+}
+
+static inline int zap_pte_range(mmu_gather_t *tlb, pmd_t * pmd, unsigned long address, unsigned long size)
+{
+ unsigned long offset;
+ pte_t * ptep;
+ int freed = 0;
+
+ if (pmd_none(*pmd))
+ return 0;
+ if (pmd_bad(*pmd)) {
+ pmd_ERROR(*pmd);
+ pmd_clear(pmd);
+ return 0;
+ }
+ ptep = pte_offset(pmd, address);
+ offset = address & ~PMD_MASK;
+ if (offset + size > PMD_SIZE)
+ size = PMD_SIZE - offset;
+ size &= PAGE_MASK;
+ for (offset=0; offset < size; ptep++, offset += PAGE_SIZE) {
+ pte_t pte = *ptep;
+ if (pte_none(pte))
+ continue;
+ if (pte_present(pte)) {
+ struct page *page = pte_page(pte);
+ if (VALID_PAGE(page) && !PageReserved(page))
+ freed ++;
+ /* This will eventually call __free_pte on the pte. */
+ tlb_remove_page(tlb, ptep, address + offset);
+ } else {
+ free_swap_and_cache(pte_to_swp_entry(pte));
+ pte_clear(ptep);
+ }
+ }
+
+ return freed;
+}
+
+static inline int zap_pmd_range(mmu_gather_t *tlb, pgd_t * dir, unsigned long address, unsigned long size)
+{
+ pmd_t * pmd;
+ unsigned long end;
+ int freed;
+
+ if (pgd_none(*dir))
+ return 0;
+ if (pgd_bad(*dir)) {
+ pgd_ERROR(*dir);
+ pgd_clear(dir);
+ return 0;
+ }
+ pmd = pmd_offset(dir, address);
+ end = address + size;
+ if (end > ((address + PGDIR_SIZE) & PGDIR_MASK))
+ end = ((address + PGDIR_SIZE) & PGDIR_MASK);
+ freed = 0;
+ do {
+ freed += zap_pte_range(tlb, pmd, address, end - address);
+ address = (address + PMD_SIZE) & PMD_MASK;
+ pmd++;
+ } while (address < end);
+ return freed;
+}
+
+/*
+ * remove user pages in a given range.
+ */
+void zap_page_range(struct mm_struct *mm, unsigned long address, unsigned long size)
+{
+ mmu_gather_t *tlb;
+ pgd_t * dir;
+ unsigned long start = address, end = address + size;
+ int freed = 0;
+
+ dir = pgd_offset(mm, address);
+
+ /*
+ * This is a long-lived spinlock. That's fine.
+ * There's no contention, because the page table
+ * lock only protects against kswapd anyway, and
+ * even if kswapd happened to be looking at this
+ * process we _want_ it to get stuck.
+ */
+ if (address >= end)
+ BUG();
+ spin_lock(&mm->page_table_lock);
+ flush_cache_range(mm, address, end);
+ tlb = tlb_gather_mmu(mm);
+
+ do {
+ freed += zap_pmd_range(tlb, dir, address, end - address);
+ address = (address + PGDIR_SIZE) & PGDIR_MASK;
+ dir++;
+ } while (address && (address < end));
+
+ /* this will flush any remaining tlb entries */
+ tlb_finish_mmu(tlb, start, end);
+
+ /*
+ * Update rss for the mm_struct (not necessarily current->mm)
+ * Notice that rss is an unsigned long.
+ */
+ if (mm->rss > freed)
+ mm->rss -= freed;
+ else
+ mm->rss = 0;
+ spin_unlock(&mm->page_table_lock);
+}
+
+/*
+ * Do a quick page-table lookup for a single page.
+ */
+static struct page * follow_page(struct mm_struct *mm, unsigned long address, int write)
+{
+ pgd_t *pgd;
+ pmd_t *pmd;
+ pte_t *ptep, pte;
+
+ pgd = pgd_offset(mm, address);
+ if (pgd_none(*pgd) || pgd_bad(*pgd))
+ goto out;
+
+ pmd = pmd_offset(pgd, address);
+ if (pmd_none(*pmd) || pmd_bad(*pmd))
+ goto out;
+
+ ptep = pte_offset(pmd, address);
+ if (!ptep)
+ goto out;
+
+ pte = *ptep;
+ if (pte_present(pte)) {
+ if (!write ||
+ (pte_write(pte) && pte_dirty(pte)))
+ return pte_page(pte);
+ }
+
+out:
+ return 0;
+}
+
+/*
+ * Given a physical address, is there a useful struct page pointing to
+ * it? This may become more complex in the future if we start dealing
+ * with IO-aperture pages in kiobufs.
+ */
+
+static inline struct page * get_page_map(struct page *page)
+{
+ if (!VALID_PAGE(page))
+ return 0;
+ return page;
+}
+
+/*
+ * Please read Documentation/cachetlb.txt before using this function,
+ * accessing foreign memory spaces can cause cache coherency problems.
+ *
+ * Accessing a VM_IO area is even more dangerous, therefore the function
+ * fails if pages is != NULL and a VM_IO area is found.
+ */
+int get_user_pages(struct task_struct *tsk, struct mm_struct *mm, unsigned long start,
+ int len, int write, int force, struct page **pages, struct vm_area_struct **vmas)
+{
+ int i;
+ unsigned int flags;
+
+ /*
+ * Require read or write permissions.
+ * If 'force' is set, we only require the "MAY" flags.
+ */
+ flags = write ? (VM_WRITE | VM_MAYWRITE) : (VM_READ | VM_MAYREAD);
+ flags &= force ? (VM_MAYREAD | VM_MAYWRITE) : (VM_READ | VM_WRITE);
+ i = 0;
+
+ do {
+ struct vm_area_struct * vma;
+
+ vma = find_extend_vma(mm, start);
+
+ if ( !vma || (pages && vma->vm_flags & VM_IO) || !(flags & vma->vm_flags) )
+ return i ? : -EFAULT;
+
+ spin_lock(&mm->page_table_lock);
+ do {
+ struct page *map;
+ while (!(map = follow_page(mm, start, write))) {
+ spin_unlock(&mm->page_table_lock);
+ switch (handle_mm_fault(mm, vma, start, write)) {
+ case 1:
+ tsk->min_flt++;
+ break;
+ case 2:
+ tsk->maj_flt++;
+ break;
+ case 0:
+ if (i) return i;
+ return -EFAULT;
+ default:
+ if (i) return i;
+ return -ENOMEM;
+ }
+ spin_lock(&mm->page_table_lock);
+ }
+ if (pages) {
+ pages[i] = get_page_map(map);
+ /* FIXME: call the correct function,
+ * depending on the type of the found page
+ */
+ if (!pages[i])
+ goto bad_page;
+ page_cache_get(pages[i]);
+ }
+ if (vmas)
+ vmas[i] = vma;
+ i++;
+ start += PAGE_SIZE;
+ len--;
+ } while(len && start < vma->vm_end);
+ spin_unlock(&mm->page_table_lock);
+ } while(len);
+out:
+ return i;
+
+ /*
+ * We found an invalid page in the VMA. Release all we have
+ * so far and fail.
+ */
+bad_page:
+ spin_unlock(&mm->page_table_lock);
+ while (i--)
+ page_cache_release(pages[i]);
+ i = -EFAULT;
+ goto out;
+}
+
+EXPORT_SYMBOL(get_user_pages);
+
+/*
+ * Force in an entire range of pages from the current process's user VA,
+ * and pin them in physical memory.
+ */
+#define dprintk(x...)
+
+int map_user_kiobuf(int rw, struct kiobuf *iobuf, unsigned long va, size_t len)
+{
+ int pgcount, err;
+ struct mm_struct * mm;
+
+ /* Make sure the iobuf is not already mapped somewhere. */
+ if (iobuf->nr_pages)
+ return -EINVAL;
+
+ mm = current->mm;
+ dprintk ("map_user_kiobuf: begin\n");
+
+ pgcount = (va + len + PAGE_SIZE - 1)/PAGE_SIZE - va/PAGE_SIZE;
+ /* mapping 0 bytes is not permitted */
+ if (!pgcount) BUG();
+ err = expand_kiobuf(iobuf, pgcount);
+ if (err)
+ return err;
+
+ iobuf->locked = 0;
+ iobuf->offset = va & (PAGE_SIZE-1);
+ iobuf->length = len;
+
+ /* Try to fault in all of the necessary pages */
+ down_read(&mm->mmap_sem);
+ /* rw==READ means read from disk, write into memory area */
+ err = get_user_pages(current, mm, va, pgcount,
+ (rw==READ), 0, iobuf->maplist, NULL);
+ up_read(&mm->mmap_sem);
+ if (err < 0) {
+ unmap_kiobuf(iobuf);
+ dprintk ("map_user_kiobuf: end %d\n", err);
+ return err;
+ }
+ iobuf->nr_pages = err;
+ while (pgcount--) {
+ /* FIXME: flush superflous for rw==READ,
+ * probably wrong function for rw==WRITE
+ */
+ flush_dcache_page(iobuf->maplist[pgcount]);
+ }
+ dprintk ("map_user_kiobuf: end OK\n");
+ return 0;
+}
+
+/*
+ * Mark all of the pages in a kiobuf as dirty
+ *
+ * We need to be able to deal with short reads from disk: if an IO error
+ * occurs, the number of bytes read into memory may be less than the
+ * size of the kiobuf, so we have to stop marking pages dirty once the
+ * requested byte count has been reached.
+ *
+ * Must be called from process context - set_page_dirty() takes VFS locks.
+ */
+
+void mark_dirty_kiobuf(struct kiobuf *iobuf, int bytes)
+{
+ int index, offset, remaining;
+ struct page *page;
+
+ index = iobuf->offset >> PAGE_SHIFT;
+ offset = iobuf->offset & ~PAGE_MASK;
+ remaining = bytes;
+ if (remaining > iobuf->length)
+ remaining = iobuf->length;
+
+ while (remaining > 0 && index < iobuf->nr_pages) {
+ page = iobuf->maplist[index];
+
+ if (!PageReserved(page))
+ set_page_dirty(page);
+
+ remaining -= (PAGE_SIZE - offset);
+ offset = 0;
+ index++;
+ }
+}
+
+/*
+ * Unmap all of the pages referenced by a kiobuf. We release the pages,
+ * and unlock them if they were locked.
+ */
+
+void unmap_kiobuf (struct kiobuf *iobuf)
+{
+ int i;
+ struct page *map;
+
+ for (i = 0; i < iobuf->nr_pages; i++) {
+ map = iobuf->maplist[i];
+ if (map) {
+ if (iobuf->locked)
+ UnlockPage(map);
+ /* FIXME: cache flush missing for rw==READ
+ * FIXME: call the correct reference counting function
+ */
+ page_cache_release(map);
+ }
+ }
+
+ iobuf->nr_pages = 0;
+ iobuf->locked = 0;
+}
+
+
+/*
+ * Lock down all of the pages of a kiovec for IO.
+ *
+ * If any page is mapped twice in the kiovec, we return the error -EINVAL.
+ *
+ * The optional wait parameter causes the lock call to block until all
+ * pages can be locked if set. If wait==0, the lock operation is
+ * aborted if any locked pages are found and -EAGAIN is returned.
+ */
+
+int lock_kiovec(int nr, struct kiobuf *iovec[], int wait)
+{
+ struct kiobuf *iobuf;
+ int i, j;
+ struct page *page, **ppage;
+ int doublepage = 0;
+ int repeat = 0;
+
+ repeat:
+
+ for (i = 0; i < nr; i++) {
+ iobuf = iovec[i];
+
+ if (iobuf->locked)
+ continue;
+
+ ppage = iobuf->maplist;
+ for (j = 0; j < iobuf->nr_pages; ppage++, j++) {
+ page = *ppage;
+ if (!page)
+ continue;
+
+ if (TryLockPage(page)) {
+ while (j--) {
+ struct page *tmp = *--ppage;
+ if (tmp)
+ UnlockPage(tmp);
+ }
+ goto retry;
+ }
+ }
+ iobuf->locked = 1;
+ }
+
+ return 0;
+
+ retry:
+
+ /*
+ * We couldn't lock one of the pages. Undo the locking so far,
+ * wait on the page we got to, and try again.
+ */
+
+ unlock_kiovec(nr, iovec);
+ if (!wait)
+ return -EAGAIN;
+
+ /*
+ * Did the release also unlock the page we got stuck on?
+ */
+ if (!PageLocked(page)) {
+ /*
+ * If so, we may well have the page mapped twice
+ * in the IO address range. Bad news. Of
+ * course, it _might_ just be a coincidence,
+ * but if it happens more than once, chances
+ * are we have a double-mapped page.
+ */
+ if (++doublepage >= 3)
+ return -EINVAL;
+
+ /* Try again... */
+ wait_on_page(page);
+ }
+
+ if (++repeat < 16)
+ goto repeat;
+ return -EAGAIN;
+}
+
+/*
+ * Unlock all of the pages of a kiovec after IO.
+ */
+
+int unlock_kiovec(int nr, struct kiobuf *iovec[])
+{
+ struct kiobuf *iobuf;
+ int i, j;
+ struct page *page, **ppage;
+
+ for (i = 0; i < nr; i++) {
+ iobuf = iovec[i];
+
+ if (!iobuf->locked)
+ continue;
+ iobuf->locked = 0;
+
+ ppage = iobuf->maplist;
+ for (j = 0; j < iobuf->nr_pages; ppage++, j++) {
+ page = *ppage;
+ if (!page)
+ continue;
+ UnlockPage(page);
+ }
+ }
+ return 0;
+}
+
+static inline void zeromap_pte_range(pte_t * pte, unsigned long address,
+ unsigned long size, pgprot_t prot)
+{
+ unsigned long end;
+
+ address &= ~PMD_MASK;
+ end = address + size;
+ if (end > PMD_SIZE)
+ end = PMD_SIZE;
+ do {
+ pte_t zero_pte = pte_wrprotect(mk_pte(ZERO_PAGE(address), prot));
+ pte_t oldpage = ptep_get_and_clear(pte);
+ set_pte(pte, zero_pte);
+ forget_pte(oldpage);
+ address += PAGE_SIZE;
+ pte++;
+ } while (address && (address < end));
+}
+
+static inline int zeromap_pmd_range(struct mm_struct *mm, pmd_t * pmd, unsigned long address,
+ unsigned long size, pgprot_t prot)
+{
+ unsigned long end;
+
+ address &= ~PGDIR_MASK;
+ end = address + size;
+ if (end > PGDIR_SIZE)
+ end = PGDIR_SIZE;
+ do {
+ pte_t * pte = pte_alloc(mm, pmd, address);
+ if (!pte)
+ return -ENOMEM;
+ zeromap_pte_range(pte, address, end - address, prot);
+ address = (address + PMD_SIZE) & PMD_MASK;
+ pmd++;
+ } while (address && (address < end));
+ return 0;
+}
+
+int zeromap_page_range(unsigned long address, unsigned long size, pgprot_t prot)
+{
+ int error = 0;
+ pgd_t * dir;
+ unsigned long beg = address;
+ unsigned long end = address + size;
+ struct mm_struct *mm = current->mm;
+
+ dir = pgd_offset(mm, address);
+ flush_cache_range(mm, beg, end);
+ if (address >= end)
+ BUG();
+
+ spin_lock(&mm->page_table_lock);
+ do {
+ pmd_t *pmd = pmd_alloc(mm, dir, address);
+ error = -ENOMEM;
+ if (!pmd)
+ break;
+ error = zeromap_pmd_range(mm, pmd, address, end - address, prot);
+ if (error)
+ break;
+ address = (address + PGDIR_SIZE) & PGDIR_MASK;
+ dir++;
+ } while (address && (address < end));
+ spin_unlock(&mm->page_table_lock);
+ flush_tlb_range(mm, beg, end);
+ return error;
+}
+
+/*
+ * maps a range of physical memory into the requested pages. the old
+ * mappings are removed. any references to nonexistent pages results
+ * in null mappings (currently treated as "copy-on-access")
+ */
+static inline void remap_pte_range(pte_t * pte, unsigned long address, unsigned long size,
+ unsigned long phys_addr, pgprot_t prot)
+{
+ unsigned long end;
+
+ address &= ~PMD_MASK;
+ end = address + size;
+ if (end > PMD_SIZE)
+ end = PMD_SIZE;
+ do {
+ struct page *page;
+ pte_t oldpage;
+ oldpage = ptep_get_and_clear(pte);
+
+ page = virt_to_page(__va(phys_addr));
+ if ((!VALID_PAGE(page)) || PageReserved(page))
+ set_pte(pte, mk_pte_phys(phys_addr, prot));
+ forget_pte(oldpage);
+ address += PAGE_SIZE;
+ phys_addr += PAGE_SIZE;
+ pte++;
+ } while (address && (address < end));
+}
+
+static inline int remap_pmd_range(struct mm_struct *mm, pmd_t * pmd, unsigned long address, unsigned long size,
+ unsigned long phys_addr, pgprot_t prot)
+{
+ unsigned long end;
+
+ address &= ~PGDIR_MASK;
+ end = address + size;
+ if (end > PGDIR_SIZE)
+ end = PGDIR_SIZE;
+ phys_addr -= address;
+ do {
+ pte_t * pte = pte_alloc(mm, pmd, address);
+ if (!pte)
+ return -ENOMEM;
+ remap_pte_range(pte, address, end - address, address + phys_addr, prot);
+ address = (address + PMD_SIZE) & PMD_MASK;
+ pmd++;
+ } while (address && (address < end));
+ return 0;
+}
+
+/* Note: this is only safe if the mm semaphore is held when called. */
+int remap_page_range(unsigned long from, unsigned long phys_addr, unsigned long size, pgprot_t prot)
+{
+ int error = 0;
+ pgd_t * dir;
+ unsigned long beg = from;
+ unsigned long end = from + size;
+ struct mm_struct *mm = current->mm;
+
+ phys_addr -= from;
+ dir = pgd_offset(mm, from);
+ flush_cache_range(mm, beg, end);
+ if (from >= end)
+ BUG();
+
+ spin_lock(&mm->page_table_lock);
+ do {
+ pmd_t *pmd = pmd_alloc(mm, dir, from);
+ error = -ENOMEM;
+ if (!pmd)
+ break;
+ error = remap_pmd_range(mm, pmd, from, end - from, phys_addr + from, prot);
+ if (error)
+ break;
+ from = (from + PGDIR_SIZE) & PGDIR_MASK;
+ dir++;
+ } while (from && (from < end));
+ spin_unlock(&mm->page_table_lock);
+ flush_tlb_range(mm, beg, end);
+ return error;
+}
+
+/*
+ * Establish a new mapping:
+ * - flush the old one
+ * - update the page tables
+ * - inform the TLB about the new one
+ *
+ * We hold the mm semaphore for reading and vma->vm_mm->page_table_lock
+ */
+static inline void establish_pte(struct vm_area_struct * vma, unsigned long address, pte_t *page_table, pte_t entry)
+{
+ set_pte(page_table, entry);
+ flush_tlb_page(vma, address);
+ update_mmu_cache(vma, address, entry);
+}
+
+/*
+ * We hold the mm semaphore for reading and vma->vm_mm->page_table_lock
+ */
+static inline void break_cow(struct vm_area_struct * vma, struct page * new_page, unsigned long address,
+ pte_t *page_table)
+{
+ flush_page_to_ram(new_page);
+ flush_cache_page(vma, address);
+ establish_pte(vma, address, page_table, pte_mkwrite(pte_mkdirty(mk_pte(new_page, vma->vm_page_prot))));
+}
+
+/*
+ * This routine handles present pages, when users try to write
+ * to a shared page. It is done by copying the page to a new address
+ * and decrementing the shared-page counter for the old page.
+ *
+ * Goto-purists beware: the only reason for goto's here is that it results
+ * in better assembly code.. The "default" path will see no jumps at all.
+ *
+ * Note that this routine assumes that the protection checks have been
+ * done by the caller (the low-level page fault routine in most cases).
+ * Thus we can safely just mark it writable once we've done any necessary
+ * COW.
+ *
+ * We also mark the page dirty at this point even though the page will
+ * change only once the write actually happens. This avoids a few races,
+ * and potentially makes it more efficient.
+ *
+ * We hold the mm semaphore and the page_table_lock on entry and exit
+ * with the page_table_lock released.
+ */
+static int do_wp_page(struct mm_struct *mm, struct vm_area_struct * vma,
+ unsigned long address, pte_t *page_table, pte_t pte)
+{
+ struct page *old_page, *new_page;
+
+ old_page = pte_page(pte);
+ if (!VALID_PAGE(old_page))
+ goto bad_wp_page;
+
+ if (!TryLockPage(old_page)) {
+ int reuse = can_share_swap_page(old_page);
+ unlock_page(old_page);
+ if (reuse) {
+ flush_cache_page(vma, address);
+ establish_pte(vma, address, page_table, pte_mkyoung(pte_mkdirty(pte_mkwrite(pte))));
+ spin_unlock(&mm->page_table_lock);
+ return 1; /* Minor fault */
+ }
+ }
+
+ /*
+ * Ok, we need to copy. Oh, well..
+ */
+ page_cache_get(old_page);
+ spin_unlock(&mm->page_table_lock);
+
+ new_page = alloc_page(GFP_HIGHUSER);
+ if (!new_page)
+ goto no_mem;
+ copy_cow_page(old_page,new_page,address);
+
+ /*
+ * Re-check the pte - we dropped the lock
+ */
+ spin_lock(&mm->page_table_lock);
+ if (pte_same(*page_table, pte)) {
+ if (PageReserved(old_page))
+ ++mm->rss;
+ break_cow(vma, new_page, address, page_table);
+ lru_cache_add(new_page);
+
+ /* Free the old page.. */
+ new_page = old_page;
+ }
+ spin_unlock(&mm->page_table_lock);
+ page_cache_release(new_page);
+ page_cache_release(old_page);
+ return 1; /* Minor fault */
+
+bad_wp_page:
+ spin_unlock(&mm->page_table_lock);
+ printk("do_wp_page: bogus page at address %08lx (page 0x%lx)\n",address,(unsigned long)old_page);
+ return -1;
+no_mem:
+ page_cache_release(old_page);
+ return -1;
+}
+
+static void vmtruncate_list(struct vm_area_struct *mpnt, unsigned long pgoff)
+{
+ do {
+ struct mm_struct *mm = mpnt->vm_mm;
+ unsigned long start = mpnt->vm_start;
+ unsigned long end = mpnt->vm_end;
+ unsigned long len = end - start;
+ unsigned long diff;
+
+ /* mapping wholly truncated? */
+ if (mpnt->vm_pgoff >= pgoff) {
+ zap_page_range(mm, start, len);
+ continue;
+ }
+
+ /* mapping wholly unaffected? */
+ len = len >> PAGE_SHIFT;
+ diff = pgoff - mpnt->vm_pgoff;
+ if (diff >= len)
+ continue;
+
+ /* Ok, partially affected.. */
+ start += diff << PAGE_SHIFT;
+ len = (len - diff) << PAGE_SHIFT;
+ zap_page_range(mm, start, len);
+ } while ((mpnt = mpnt->vm_next_share) != NULL);
+}
+
+/*
+ * Handle all mappings that got truncated by a "truncate()"
+ * system call.
+ *
+ * NOTE! We have to be ready to update the memory sharing
+ * between the file and the memory map for a potential last
+ * incomplete page. Ugly, but necessary.
+ */
+int vmtruncate(struct inode * inode, loff_t offset)
+{
+ unsigned long pgoff;
+ struct address_space *mapping = inode->i_mapping;
+ unsigned long limit;
+
+ if (inode->i_size < offset)
+ goto do_expand;
+ inode->i_size = offset;
+ spin_lock(&mapping->i_shared_lock);
+ if (!mapping->i_mmap && !mapping->i_mmap_shared)
+ goto out_unlock;
+
+ pgoff = (offset + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
+ if (mapping->i_mmap != NULL)
+ vmtruncate_list(mapping->i_mmap, pgoff);
+ if (mapping->i_mmap_shared != NULL)
+ vmtruncate_list(mapping->i_mmap_shared, pgoff);
+
+out_unlock:
+ spin_unlock(&mapping->i_shared_lock);
+ truncate_inode_pages(mapping, offset);
+ goto out_truncate;
+
+do_expand:
+ limit = current->rlim[RLIMIT_FSIZE].rlim_cur;
+ if (limit != RLIM_INFINITY && offset > limit)
+ goto out_sig;
+ if (offset > inode->i_sb->s_maxbytes)
+ goto out;
+ inode->i_size = offset;
+
+out_truncate:
+ if (inode->i_op && inode->i_op->truncate) {
+ lock_kernel();
+ inode->i_op->truncate(inode);
+ unlock_kernel();
+ }
+ return 0;
+out_sig:
+ send_sig(SIGXFSZ, current, 0);
+out:
+ return -EFBIG;
+}
+
+/*
+ * Primitive swap readahead code. We simply read an aligned block of
+ * (1 << page_cluster) entries in the swap area. This method is chosen
+ * because it doesn't cost us any seek time. We also make sure to queue
+ * the 'original' request together with the readahead ones...
+ */
+void swapin_readahead(swp_entry_t entry)
+{
+ int i, num;
+ struct page *new_page;
+ unsigned long offset;
+
+ /*
+ * Get the number of handles we should do readahead io to.
+ */
+ num = valid_swaphandles(entry, &offset);
+ for (i = 0; i < num; offset++, i++) {
+ /* Ok, do the async read-ahead now */
+ new_page = read_swap_cache_async(SWP_ENTRY(SWP_TYPE(entry), offset));
+ if (!new_page)
+ break;
+ page_cache_release(new_page);
+ }
+ return;
+}
+
+/*
+ * We hold the mm semaphore and the page_table_lock on entry and
+ * should release the pagetable lock on exit..
+ */
+static int do_swap_page(struct mm_struct * mm,
+ struct vm_area_struct * vma, unsigned long address,
+ pte_t * page_table, pte_t orig_pte, int write_access)
+{
+ struct page *page;
+ swp_entry_t entry = pte_to_swp_entry(orig_pte);
+ pte_t pte;
+ int ret = 1;
+
+ spin_unlock(&mm->page_table_lock);
+ page = lookup_swap_cache(entry);
+ if (!page) {
+ swapin_readahead(entry);
+ page = read_swap_cache_async(entry);
+ if (!page) {
+ /*
+ * Back out if somebody else faulted in this pte while
+ * we released the page table lock.
+ */
+ int retval;
+ spin_lock(&mm->page_table_lock);
+ retval = pte_same(*page_table, orig_pte) ? -1 : 1;
+ spin_unlock(&mm->page_table_lock);
+ return retval;
+ }
+
+ /* Had to read the page from swap area: Major fault */
+ ret = 2;
+ }
+
+ mark_page_accessed(page);
+
+ lock_page(page);
+
+ /*
+ * Back out if somebody else faulted in this pte while we
+ * released the page table lock.
+ */
+ spin_lock(&mm->page_table_lock);
+ if (!pte_same(*page_table, orig_pte)) {
+ spin_unlock(&mm->page_table_lock);
+ unlock_page(page);
+ page_cache_release(page);
+ return 1;
+ }
+
+ /* The page isn't present yet, go ahead with the fault. */
+
+ swap_free(entry);
+ if (vm_swap_full())
+ remove_exclusive_swap_page(page);
+
+ mm->rss++;
+ pte = mk_pte(page, vma->vm_page_prot);
+ if (write_access && can_share_swap_page(page))
+ pte = pte_mkdirty(pte_mkwrite(pte));
+ unlock_page(page);
+
+ flush_page_to_ram(page);
+ flush_icache_page(vma, page);
+ set_pte(page_table, pte);
+
+ /* No need to invalidate - it was non-present before */
+ update_mmu_cache(vma, address, pte);
+ XENO_flush_page_update_queue();
+ spin_unlock(&mm->page_table_lock);
+ return ret;
+}
+
+/*
+ * We are called with the MM semaphore and page_table_lock
+ * spinlock held to protect against concurrent faults in
+ * multithreaded programs.
+ */
+static int do_anonymous_page(struct mm_struct * mm, struct vm_area_struct * vma, pte_t *page_table, int write_access, unsigned long addr)
+{
+ pte_t entry;
+
+ /* Read-only mapping of ZERO_PAGE. */
+ entry = pte_wrprotect(mk_pte(ZERO_PAGE(addr), vma->vm_page_prot));
+
+ /* ..except if it's a write access */
+ if (write_access) {
+ struct page *page;
+
+ /* Allocate our own private page. */
+ spin_unlock(&mm->page_table_lock);
+
+ page = alloc_page(GFP_HIGHUSER);
+ if (!page)
+ goto no_mem;
+ clear_user_highpage(page, addr);
+
+ spin_lock(&mm->page_table_lock);
+ if (!pte_none(*page_table)) {
+ page_cache_release(page);
+ spin_unlock(&mm->page_table_lock);
+ return 1;
+ }
+ mm->rss++;
+ flush_page_to_ram(page);
+ entry = pte_mkwrite(pte_mkdirty(mk_pte(page, vma->vm_page_prot)));
+ lru_cache_add(page);
+ mark_page_accessed(page);
+ }
+
+ set_pte(page_table, entry);
+
+ /* No need to invalidate - it was non-present before */
+ update_mmu_cache(vma, addr, entry);
+ XENO_flush_page_update_queue();
+ spin_unlock(&mm->page_table_lock);
+ return 1; /* Minor fault */
+
+no_mem:
+ return -1;
+}
+
+/*
+ * do_no_page() tries to create a new page mapping. It aggressively
+ * tries to share with existing pages, but makes a separate copy if
+ * the "write_access" parameter is true in order to avoid the next
+ * page fault.
+ *
+ * As this is called only for pages that do not currently exist, we
+ * do not need to flush old virtual caches or the TLB.
+ *
+ * This is called with the MM semaphore held and the page table
+ * spinlock held. Exit with the spinlock released.
+ */
+static int do_no_page(struct mm_struct * mm, struct vm_area_struct * vma,
+ unsigned long address, int write_access, pte_t *page_table)
+{
+ struct page * new_page;
+ pte_t entry;
+
+ if (!vma->vm_ops || !vma->vm_ops->nopage)
+ return do_anonymous_page(mm, vma, page_table, write_access, address);
+ spin_unlock(&mm->page_table_lock);
+
+ new_page = vma->vm_ops->nopage(vma, address & PAGE_MASK, 0);
+
+ if (new_page == NULL) /* no page was available -- SIGBUS */
+ return 0;
+ if (new_page == NOPAGE_OOM)
+ return -1;
+
+ /*
+ * Should we do an early C-O-W break?
+ */
+ if (write_access && !(vma->vm_flags & VM_SHARED)) {
+ struct page * page = alloc_page(GFP_HIGHUSER);
+ if (!page) {
+ page_cache_release(new_page);
+ return -1;
+ }
+ copy_user_highpage(page, new_page, address);
+ page_cache_release(new_page);
+ lru_cache_add(page);
+ new_page = page;
+ }
+
+ spin_lock(&mm->page_table_lock);
+ /*
+ * This silly early PAGE_DIRTY setting removes a race
+ * due to the bad i386 page protection. But it's valid
+ * for other architectures too.
+ *
+ * Note that if write_access is true, we either now have
+ * an exclusive copy of the page, or this is a shared mapping,
+ * so we can make it writable and dirty to avoid having to
+ * handle that later.
+ */
+ /* Only go through if we didn't race with anybody else... */
+ if (pte_none(*page_table)) {
+ ++mm->rss;
+ flush_page_to_ram(new_page);
+ flush_icache_page(vma, new_page);
+ entry = mk_pte(new_page, vma->vm_page_prot);
+ if (write_access)
+ entry = pte_mkwrite(pte_mkdirty(entry));
+ set_pte(page_table, entry);
+ } else {
+ /* One of our sibling threads was faster, back out. */
+ page_cache_release(new_page);
+ spin_unlock(&mm->page_table_lock);
+ return 1;
+ }
+
+ /* no need to invalidate: a not-present page shouldn't be cached */
+ update_mmu_cache(vma, address, entry);
+ XENO_flush_page_update_queue();
+ spin_unlock(&mm->page_table_lock);
+ return 2; /* Major fault */
+}
+
+/*
+ * These routines also need to handle stuff like marking pages dirty
+ * and/or accessed for architectures that don't do it in hardware (most
+ * RISC architectures). The early dirtying is also good on the i386.
+ *
+ * There is also a hook called "update_mmu_cache()" that architectures
+ * with external mmu caches can use to update those (ie the Sparc or
+ * PowerPC hashed page tables that act as extended TLBs).
+ *
+ * Note the "page_table_lock". It is to protect against kswapd removing
+ * pages from under us. Note that kswapd only ever _removes_ pages, never
+ * adds them. As such, once we have noticed that the page is not present,
+ * we can drop the lock early.
+ *
+ * The adding of pages is protected by the MM semaphore (which we hold),
+ * so we don't need to worry about a page being suddenly been added into
+ * our VM.
+ *
+ * We enter with the pagetable spinlock held, we are supposed to
+ * release it when done.
+ */
+static inline int handle_pte_fault(struct mm_struct *mm,
+ struct vm_area_struct * vma, unsigned long address,
+ int write_access, pte_t * pte)
+{
+ pte_t entry;
+
+ entry = *pte;
+ if (!pte_present(entry)) {
+ /*
+ * If it truly wasn't present, we know that kswapd
+ * and the PTE updates will not touch it later. So
+ * drop the lock.
+ */
+ if (pte_none(entry))
+ return do_no_page(mm, vma, address, write_access, pte);
+ return do_swap_page(mm, vma, address, pte, entry, write_access);
+ }
+
+ if (write_access) {
+ if (!pte_write(entry))
+ return do_wp_page(mm, vma, address, pte, entry);
+
+ entry = pte_mkdirty(entry);
+ }
+ entry = pte_mkyoung(entry);
+ establish_pte(vma, address, pte, entry);
+ XENO_flush_page_update_queue();
+ spin_unlock(&mm->page_table_lock);
+ return 1;
+}
+
+/*
+ * By the time we get here, we already hold the mm semaphore
+ */
+int handle_mm_fault(struct mm_struct *mm, struct vm_area_struct * vma,
+ unsigned long address, int write_access)
+{
+ pgd_t *pgd;
+ pmd_t *pmd;
+
+ current->state = TASK_RUNNING;
+ pgd = pgd_offset(mm, address);
+
+ /*
+ * We need the page table lock to synchronize with kswapd
+ * and the SMP-safe atomic PTE updates.
+ */
+ spin_lock(&mm->page_table_lock);
+ pmd = pmd_alloc(mm, pgd, address);
+
+ if (pmd) {
+ pte_t * pte = pte_alloc(mm, pmd, address);
+ if (pte)
+ return handle_pte_fault(mm, vma, address, write_access, pte);
+ }
+ spin_unlock(&mm->page_table_lock);
+ return -1;
+}
+
+/*
+ * Allocate page middle directory.
+ *
+ * We've already handled the fast-path in-line, and we own the
+ * page table lock.
+ *
+ * On a two-level page table, this ends up actually being entirely
+ * optimized away.
+ */
+pmd_t *__pmd_alloc(struct mm_struct *mm, pgd_t *pgd, unsigned long address)
+{
+ pmd_t *new;
+
+ /* "fast" allocation can happen without dropping the lock.. */
+ new = pmd_alloc_one_fast(mm, address);
+ if (!new) {
+ spin_unlock(&mm->page_table_lock);
+ new = pmd_alloc_one(mm, address);
+ spin_lock(&mm->page_table_lock);
+ if (!new)
+ return NULL;
+
+ /*
+ * Because we dropped the lock, we should re-check the
+ * entry, as somebody else could have populated it..
+ */
+ if (!pgd_none(*pgd)) {
+ pmd_free(new);
+ goto out;
+ }
+ }
+ pgd_populate(mm, pgd, new);
+out:
+ return pmd_offset(pgd, address);
+}
+
+/*
+ * Allocate the page table directory.
+ *
+ * We've already handled the fast-path in-line, and we own the
+ * page table lock.
+ */
+pte_t *pte_alloc(struct mm_struct *mm, pmd_t *pmd, unsigned long address)
+{
+ if (pmd_none(*pmd)) {
+ pte_t *new;
+
+ /* "fast" allocation can happen without dropping the lock.. */
+ new = pte_alloc_one_fast(mm, address);
+ if (!new) {
+ XENO_flush_page_update_queue();
+ spin_unlock(&mm->page_table_lock);
+ new = pte_alloc_one(mm, address);
+ spin_lock(&mm->page_table_lock);
+ if (!new)
+ return NULL;
+
+ /*
+ * Because we dropped the lock, we should re-check the
+ * entry, as somebody else could have populated it..
+ */
+ if (!pmd_none(*pmd)) {
+ pte_free(new);
+ goto out;
+ }
+ }
+ pmd_populate(mm, pmd, new);
+ }
+out:
+ return pte_offset(pmd, address);
+}
+
+int make_pages_present(unsigned long addr, unsigned long end)
+{
+ int ret, len, write;
+ struct vm_area_struct * vma;
+
+ vma = find_vma(current->mm, addr);
+ write = (vma->vm_flags & VM_WRITE) != 0;
+ if (addr >= end)
+ BUG();
+ if (end > vma->vm_end)
+ BUG();
+ len = (end+PAGE_SIZE-1)/PAGE_SIZE-addr/PAGE_SIZE;
+ ret = get_user_pages(current, current->mm, addr,
+ len, write, 0, NULL, NULL);
+ return ret == len ? 0 : -1;
+}
+
+struct page * vmalloc_to_page(void * vmalloc_addr)
+{
+ unsigned long addr = (unsigned long) vmalloc_addr;
+ struct page *page = NULL;
+ pmd_t *pmd;
+ pte_t *pte;
+ pgd_t *pgd;
+
+ pgd = pgd_offset_k(addr);
+ if (!pgd_none(*pgd)) {
+ pmd = pmd_offset(pgd, addr);
+ if (!pmd_none(*pmd)) {
+ pte = pte_offset(pmd, addr);
+ if (pte_present(*pte)) {
+ page = pte_page(*pte);
+ }
+ }
+ }
+ return page;
+}
--- /dev/null
+/*
+ * linux/mm/remap.c
+ *
+ * (C) Copyright 1996 Linus Torvalds
+ */
+
+#include <linux/slab.h>
+#include <linux/smp_lock.h>
+#include <linux/shm.h>
+#include <linux/mman.h>
+#include <linux/swap.h>
+
+#include <asm/uaccess.h>
+#include <asm/pgalloc.h>
+
+extern int vm_enough_memory(long pages);
+
+static inline pte_t *get_one_pte(struct mm_struct *mm, unsigned long addr)
+{
+ pgd_t * pgd;
+ pmd_t * pmd;
+ pte_t * pte = NULL;
+
+ pgd = pgd_offset(mm, addr);
+ if (pgd_none(*pgd))
+ goto end;
+ if (pgd_bad(*pgd)) {
+ pgd_ERROR(*pgd);
+ pgd_clear(pgd);
+ goto end;
+ }
+
+ pmd = pmd_offset(pgd, addr);
+ if (pmd_none(*pmd))
+ goto end;
+ if (pmd_bad(*pmd)) {
+ pmd_ERROR(*pmd);
+ pmd_clear(pmd);
+ goto end;
+ }
+
+ pte = pte_offset(pmd, addr);
+ if (pte_none(*pte))
+ pte = NULL;
+end:
+ return pte;
+}
+
+static inline pte_t *alloc_one_pte(struct mm_struct *mm, unsigned long addr)
+{
+ pmd_t * pmd;
+ pte_t * pte = NULL;
+
+ pmd = pmd_alloc(mm, pgd_offset(mm, addr), addr);
+ if (pmd)
+ pte = pte_alloc(mm, pmd, addr);
+ return pte;
+}
+
+static inline int copy_one_pte(struct mm_struct *mm, pte_t * src, pte_t * dst)
+{
+ int error = 0;
+ pte_t pte;
+
+ if (!pte_none(*src)) {
+ pte = ptep_get_and_clear(src);
+ if (!dst) {
+ /* No dest? We must put it back. */
+ dst = src;
+ error++;
+ }
+ set_pte(dst, pte);
+ }
+ return error;
+}
+
+static int move_one_page(struct mm_struct *mm, unsigned long old_addr, unsigned long new_addr)
+{
+ int error = 0;
+ pte_t * src;
+
+ spin_lock(&mm->page_table_lock);
+ src = get_one_pte(mm, old_addr);
+ if (src)
+ error = copy_one_pte(mm, src, alloc_one_pte(mm, new_addr));
+ spin_unlock(&mm->page_table_lock);
+ return error;
+}
+
+static int move_page_tables(struct mm_struct * mm,
+ unsigned long new_addr, unsigned long old_addr, unsigned long len)
+{
+ unsigned long offset = len;
+
+ flush_cache_range(mm, old_addr, old_addr + len);
+
+ /*
+ * This is not the clever way to do this, but we're taking the
+ * easy way out on the assumption that most remappings will be
+ * only a few pages.. This also makes error recovery easier.
+ */
+ while (offset) {
+ offset -= PAGE_SIZE;
+ if (move_one_page(mm, old_addr + offset, new_addr + offset))
+ goto oops_we_failed;
+ }
+ flush_tlb_range(mm, old_addr, old_addr + len);
+ return 0;
+
+ /*
+ * Ok, the move failed because we didn't have enough pages for
+ * the new page table tree. This is unlikely, but we have to
+ * take the possibility into account. In that case we just move
+ * all the pages back (this will work, because we still have
+ * the old page tables)
+ */
+oops_we_failed:
+ XENO_flush_page_update_queue();
+ flush_cache_range(mm, new_addr, new_addr + len);
+ while ((offset += PAGE_SIZE) < len)
+ move_one_page(mm, new_addr + offset, old_addr + offset);
+ XENO_flush_page_update_queue();
+ zap_page_range(mm, new_addr, len);
+ return -1;
+}
+
+static inline unsigned long move_vma(struct vm_area_struct * vma,
+ unsigned long addr, unsigned long old_len, unsigned long new_len,
+ unsigned long new_addr)
+{
+ struct mm_struct * mm = vma->vm_mm;
+ struct vm_area_struct * new_vma, * next, * prev;
+ int allocated_vma;
+
+ new_vma = NULL;
+ next = find_vma_prev(mm, new_addr, &prev);
+ if (next) {
+ if (prev && prev->vm_end == new_addr &&
+ can_vma_merge(prev, vma->vm_flags) && !vma->vm_file && !(vma->vm_flags & VM_SHARED)) {
+ spin_lock(&mm->page_table_lock);
+ prev->vm_end = new_addr + new_len;
+ spin_unlock(&mm->page_table_lock);
+ new_vma = prev;
+ if (next != prev->vm_next)
+ BUG();
+ if (prev->vm_end == next->vm_start && can_vma_merge(next, prev->vm_flags)) {
+ spin_lock(&mm->page_table_lock);
+ prev->vm_end = next->vm_end;
+ __vma_unlink(mm, next, prev);
+ spin_unlock(&mm->page_table_lock);
+
+ mm->map_count--;
+ kmem_cache_free(vm_area_cachep, next);
+ }
+ } else if (next->vm_start == new_addr + new_len &&
+ can_vma_merge(next, vma->vm_flags) && !vma->vm_file && !(vma->vm_flags & VM_SHARED)) {
+ spin_lock(&mm->page_table_lock);
+ next->vm_start = new_addr;
+ spin_unlock(&mm->page_table_lock);
+ new_vma = next;
+ }
+ } else {
+ prev = find_vma(mm, new_addr-1);
+ if (prev && prev->vm_end == new_addr &&
+ can_vma_merge(prev, vma->vm_flags) && !vma->vm_file && !(vma->vm_flags & VM_SHARED)) {
+ spin_lock(&mm->page_table_lock);
+ prev->vm_end = new_addr + new_len;
+ spin_unlock(&mm->page_table_lock);
+ new_vma = prev;
+ }
+ }
+
+ allocated_vma = 0;
+ if (!new_vma) {
+ new_vma = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL);
+ if (!new_vma)
+ goto out;
+ allocated_vma = 1;
+ }
+
+ if (!move_page_tables(current->mm, new_addr, addr, old_len)) {
+ if (allocated_vma) {
+ *new_vma = *vma;
+ new_vma->vm_start = new_addr;
+ new_vma->vm_end = new_addr+new_len;
+ new_vma->vm_pgoff += (addr - vma->vm_start) >> PAGE_SHIFT;
+ new_vma->vm_raend = 0;
+ if (new_vma->vm_file)
+ get_file(new_vma->vm_file);
+ if (new_vma->vm_ops && new_vma->vm_ops->open)
+ new_vma->vm_ops->open(new_vma);
+ insert_vm_struct(current->mm, new_vma);
+ }
+ do_munmap(current->mm, addr, old_len);
+ current->mm->total_vm += new_len >> PAGE_SHIFT;
+ if (new_vma->vm_flags & VM_LOCKED) {
+ current->mm->locked_vm += new_len >> PAGE_SHIFT;
+ make_pages_present(new_vma->vm_start,
+ new_vma->vm_end);
+ }
+ return new_addr;
+ }
+ if (allocated_vma)
+ kmem_cache_free(vm_area_cachep, new_vma);
+ out:
+ return -ENOMEM;
+}
+
+/*
+ * Expand (or shrink) an existing mapping, potentially moving it at the
+ * same time (controlled by the MREMAP_MAYMOVE flag and available VM space)
+ *
+ * MREMAP_FIXED option added 5-Dec-1999 by Benjamin LaHaise
+ * This option implies MREMAP_MAYMOVE.
+ */
+unsigned long do_mremap(unsigned long addr,
+ unsigned long old_len, unsigned long new_len,
+ unsigned long flags, unsigned long new_addr)
+{
+ struct vm_area_struct *vma;
+ unsigned long ret = -EINVAL;
+
+ if (flags & ~(MREMAP_FIXED | MREMAP_MAYMOVE))
+ goto out;
+
+ if (addr & ~PAGE_MASK)
+ goto out;
+
+ old_len = PAGE_ALIGN(old_len);
+ new_len = PAGE_ALIGN(new_len);
+
+ /* new_addr is only valid if MREMAP_FIXED is specified */
+ if (flags & MREMAP_FIXED) {
+ if (new_addr & ~PAGE_MASK)
+ goto out;
+ if (!(flags & MREMAP_MAYMOVE))
+ goto out;
+
+ if (new_len > TASK_SIZE || new_addr > TASK_SIZE - new_len)
+ goto out;
+
+ /* Check if the location we're moving into overlaps the
+ * old location at all, and fail if it does.
+ */
+ if ((new_addr <= addr) && (new_addr+new_len) > addr)
+ goto out;
+
+ if ((addr <= new_addr) && (addr+old_len) > new_addr)
+ goto out;
+
+ do_munmap(current->mm, new_addr, new_len);
+ }
+
+ /*
+ * Always allow a shrinking remap: that just unmaps
+ * the unnecessary pages..
+ */
+ ret = addr;
+ if (old_len >= new_len) {
+ do_munmap(current->mm, addr+new_len, old_len - new_len);
+ if (!(flags & MREMAP_FIXED) || (new_addr == addr))
+ goto out;
+ }
+
+ /*
+ * Ok, we need to grow.. or relocate.
+ */
+ ret = -EFAULT;
+ vma = find_vma(current->mm, addr);
+ if (!vma || vma->vm_start > addr)
+ goto out;
+ /* We can't remap across vm area boundaries */
+ if (old_len > vma->vm_end - addr)
+ goto out;
+ if (vma->vm_flags & VM_DONTEXPAND) {
+ if (new_len > old_len)
+ goto out;
+ }
+ if (vma->vm_flags & VM_LOCKED) {
+ unsigned long locked = current->mm->locked_vm << PAGE_SHIFT;
+ locked += new_len - old_len;
+ ret = -EAGAIN;
+ if (locked > current->rlim[RLIMIT_MEMLOCK].rlim_cur)
+ goto out;
+ }
+ ret = -ENOMEM;
+ if ((current->mm->total_vm << PAGE_SHIFT) + (new_len - old_len)
+ > current->rlim[RLIMIT_AS].rlim_cur)
+ goto out;
+ /* Private writable mapping? Check memory availability.. */
+ if ((vma->vm_flags & (VM_SHARED | VM_WRITE)) == VM_WRITE &&
+ !(flags & MAP_NORESERVE) &&
+ !vm_enough_memory((new_len - old_len) >> PAGE_SHIFT))
+ goto out;
+
+ /* old_len exactly to the end of the area..
+ * And we're not relocating the area.
+ */
+ if (old_len == vma->vm_end - addr &&
+ !((flags & MREMAP_FIXED) && (addr != new_addr)) &&
+ (old_len != new_len || !(flags & MREMAP_MAYMOVE))) {
+ unsigned long max_addr = TASK_SIZE;
+ if (vma->vm_next)
+ max_addr = vma->vm_next->vm_start;
+ /* can we just expand the current mapping? */
+ if (max_addr - addr >= new_len) {
+ int pages = (new_len - old_len) >> PAGE_SHIFT;
+ spin_lock(&vma->vm_mm->page_table_lock);
+ vma->vm_end = addr + new_len;
+ spin_unlock(&vma->vm_mm->page_table_lock);
+ current->mm->total_vm += pages;
+ if (vma->vm_flags & VM_LOCKED) {
+ current->mm->locked_vm += pages;
+ make_pages_present(addr + old_len,
+ addr + new_len);
+ }
+ ret = addr;
+ goto out;
+ }
+ }
+
+ /*
+ * We weren't able to just expand or shrink the area,
+ * we need to create a new one and move it..
+ */
+ ret = -ENOMEM;
+ if (flags & MREMAP_MAYMOVE) {
+ if (!(flags & MREMAP_FIXED)) {
+ unsigned long map_flags = 0;
+ if (vma->vm_flags & VM_SHARED)
+ map_flags |= MAP_SHARED;
+
+ new_addr = get_unmapped_area(vma->vm_file, 0, new_len, vma->vm_pgoff, map_flags);
+ ret = new_addr;
+ if (new_addr & ~PAGE_MASK)
+ goto out;
+ }
+ ret = move_vma(vma, addr, old_len, new_len, new_addr);
+ }
+out:
+ return ret;
+}
+
+asmlinkage unsigned long sys_mremap(unsigned long addr,
+ unsigned long old_len, unsigned long new_len,
+ unsigned long flags, unsigned long new_addr)
+{
+ unsigned long ret;
+
+ down_write(¤t->mm->mmap_sem);
+ ret = do_mremap(addr, old_len, new_len, flags, new_addr);
+ up_write(¤t->mm->mmap_sem);
+ return ret;
+}
--- /dev/null
+/*
+ * linux/mm/swapfile.c
+ *
+ * Copyright (C) 1991, 1992, 1993, 1994 Linus Torvalds
+ * Swap reorganised 29.12.95, Stephen Tweedie
+ */
+
+#include <linux/slab.h>
+#include <linux/smp_lock.h>
+#include <linux/kernel_stat.h>
+#include <linux/swap.h>
+#include <linux/swapctl.h>
+#include <linux/blkdev.h> /* for blk_size */
+#include <linux/vmalloc.h>
+#include <linux/pagemap.h>
+#include <linux/shm.h>
+
+#include <asm/pgtable.h>
+
+spinlock_t swaplock = SPIN_LOCK_UNLOCKED;
+unsigned int nr_swapfiles;
+int total_swap_pages;
+static int swap_overflow;
+
+static const char Bad_file[] = "Bad swap file entry ";
+static const char Unused_file[] = "Unused swap file entry ";
+static const char Bad_offset[] = "Bad swap offset entry ";
+static const char Unused_offset[] = "Unused swap offset entry ";
+
+struct swap_list_t swap_list = {-1, -1};
+
+struct swap_info_struct swap_info[MAX_SWAPFILES];
+
+#define SWAPFILE_CLUSTER 256
+
+static inline int scan_swap_map(struct swap_info_struct *si)
+{
+ unsigned long offset;
+ /*
+ * We try to cluster swap pages by allocating them
+ * sequentially in swap. Once we've allocated
+ * SWAPFILE_CLUSTER pages this way, however, we resort to
+ * first-free allocation, starting a new cluster. This
+ * prevents us from scattering swap pages all over the entire
+ * swap partition, so that we reduce overall disk seek times
+ * between swap pages. -- sct */
+ if (si->cluster_nr) {
+ while (si->cluster_next <= si->highest_bit) {
+ offset = si->cluster_next++;
+ if (si->swap_map[offset])
+ continue;
+ si->cluster_nr--;
+ goto got_page;
+ }
+ }
+ si->cluster_nr = SWAPFILE_CLUSTER;
+
+ /* try to find an empty (even not aligned) cluster. */
+ offset = si->lowest_bit;
+ check_next_cluster:
+ if (offset+SWAPFILE_CLUSTER-1 <= si->highest_bit)
+ {
+ int nr;
+ for (nr = offset; nr < offset+SWAPFILE_CLUSTER; nr++)
+ if (si->swap_map[nr])
+ {
+ offset = nr+1;
+ goto check_next_cluster;
+ }
+ /* We found a completly empty cluster, so start
+ * using it.
+ */
+ goto got_page;
+ }
+ /* No luck, so now go finegrined as usual. -Andrea */
+ for (offset = si->lowest_bit; offset <= si->highest_bit ; offset++) {
+ if (si->swap_map[offset])
+ continue;
+ si->lowest_bit = offset+1;
+ got_page:
+ if (offset == si->lowest_bit)
+ si->lowest_bit++;
+ if (offset == si->highest_bit)
+ si->highest_bit--;
+ if (si->lowest_bit > si->highest_bit) {
+ si->lowest_bit = si->max;
+ si->highest_bit = 0;
+ }
+ si->swap_map[offset] = 1;
+ nr_swap_pages--;
+ si->cluster_next = offset+1;
+ return offset;
+ }
+ si->lowest_bit = si->max;
+ si->highest_bit = 0;
+ return 0;
+}
+
+swp_entry_t get_swap_page(void)
+{
+ struct swap_info_struct * p;
+ unsigned long offset;
+ swp_entry_t entry;
+ int type, wrapped = 0;
+
+ entry.val = 0; /* Out of memory */
+ swap_list_lock();
+ type = swap_list.next;
+ if (type < 0)
+ goto out;
+ if (nr_swap_pages <= 0)
+ goto out;
+
+ while (1) {
+ p = &swap_info[type];
+ if ((p->flags & SWP_WRITEOK) == SWP_WRITEOK) {
+ swap_device_lock(p);
+ offset = scan_swap_map(p);
+ swap_device_unlock(p);
+ if (offset) {
+ entry = SWP_ENTRY(type,offset);
+ type = swap_info[type].next;
+ if (type < 0 ||
+ p->prio != swap_info[type].prio) {
+ swap_list.next = swap_list.head;
+ } else {
+ swap_list.next = type;
+ }
+ goto out;
+ }
+ }
+ type = p->next;
+ if (!wrapped) {
+ if (type < 0 || p->prio != swap_info[type].prio) {
+ type = swap_list.head;
+ wrapped = 1;
+ }
+ } else
+ if (type < 0)
+ goto out; /* out of swap space */
+ }
+out:
+ swap_list_unlock();
+ return entry;
+}
+
+static struct swap_info_struct * swap_info_get(swp_entry_t entry)
+{
+ struct swap_info_struct * p;
+ unsigned long offset, type;
+
+ if (!entry.val)
+ goto out;
+ type = SWP_TYPE(entry);
+ if (type >= nr_swapfiles)
+ goto bad_nofile;
+ p = & swap_info[type];
+ if (!(p->flags & SWP_USED))
+ goto bad_device;
+ offset = SWP_OFFSET(entry);
+ if (offset >= p->max)
+ goto bad_offset;
+ if (!p->swap_map[offset])
+ goto bad_free;
+ swap_list_lock();
+ if (p->prio > swap_info[swap_list.next].prio)
+ swap_list.next = type;
+ swap_device_lock(p);
+ return p;
+
+bad_free:
+ printk(KERN_ERR "swap_free: %s%08lx\n", Unused_offset, entry.val);
+ goto out;
+bad_offset:
+ printk(KERN_ERR "swap_free: %s%08lx\n", Bad_offset, entry.val);
+ goto out;
+bad_device:
+ printk(KERN_ERR "swap_free: %s%08lx\n", Unused_file, entry.val);
+ goto out;
+bad_nofile:
+ printk(KERN_ERR "swap_free: %s%08lx\n", Bad_file, entry.val);
+out:
+ return NULL;
+}
+
+static void swap_info_put(struct swap_info_struct * p)
+{
+ swap_device_unlock(p);
+ swap_list_unlock();
+}
+
+static int swap_entry_free(struct swap_info_struct *p, unsigned long offset)
+{
+ int count = p->swap_map[offset];
+
+ if (count < SWAP_MAP_MAX) {
+ count--;
+ p->swap_map[offset] = count;
+ if (!count) {
+ if (offset < p->lowest_bit)
+ p->lowest_bit = offset;
+ if (offset > p->highest_bit)
+ p->highest_bit = offset;
+ nr_swap_pages++;
+ }
+ }
+ return count;
+}
+
+/*
+ * Caller has made sure that the swapdevice corresponding to entry
+ * is still around or has not been recycled.
+ */
+void swap_free(swp_entry_t entry)
+{
+ struct swap_info_struct * p;
+
+ p = swap_info_get(entry);
+ if (p) {
+ swap_entry_free(p, SWP_OFFSET(entry));
+ swap_info_put(p);
+ }
+}
+
+/*
+ * Check if we're the only user of a swap page,
+ * when the page is locked.
+ */
+static int exclusive_swap_page(struct page *page)
+{
+ int retval = 0;
+ struct swap_info_struct * p;
+ swp_entry_t entry;
+
+ entry.val = page->index;
+ p = swap_info_get(entry);
+ if (p) {
+ /* Is the only swap cache user the cache itself? */
+ if (p->swap_map[SWP_OFFSET(entry)] == 1) {
+ /* Recheck the page count with the pagecache lock held.. */
+ spin_lock(&pagecache_lock);
+ if (page_count(page) - !!page->buffers == 2)
+ retval = 1;
+ spin_unlock(&pagecache_lock);
+ }
+ swap_info_put(p);
+ }
+ return retval;
+}
+
+/*
+ * We can use this swap cache entry directly
+ * if there are no other references to it.
+ *
+ * Here "exclusive_swap_page()" does the real
+ * work, but we opportunistically check whether
+ * we need to get all the locks first..
+ */
+int can_share_swap_page(struct page *page)
+{
+ int retval = 0;
+
+ if (!PageLocked(page))
+ BUG();
+ switch (page_count(page)) {
+ case 3:
+ if (!page->buffers)
+ break;
+ /* Fallthrough */
+ case 2:
+ if (!PageSwapCache(page))
+ break;
+ retval = exclusive_swap_page(page);
+ break;
+ case 1:
+ if (PageReserved(page))
+ break;
+ retval = 1;
+ }
+ return retval;
+}
+
+/*
+ * Work out if there are any other processes sharing this
+ * swap cache page. Free it if you can. Return success.
+ */
+int remove_exclusive_swap_page(struct page *page)
+{
+ int retval;
+ struct swap_info_struct * p;
+ swp_entry_t entry;
+
+ if (!PageLocked(page))
+ BUG();
+ if (!PageSwapCache(page))
+ return 0;
+ if (page_count(page) - !!page->buffers != 2) /* 2: us + cache */
+ return 0;
+
+ entry.val = page->index;
+ p = swap_info_get(entry);
+ if (!p)
+ return 0;
+
+ /* Is the only swap cache user the cache itself? */
+ retval = 0;
+ if (p->swap_map[SWP_OFFSET(entry)] == 1) {
+ /* Recheck the page count with the pagecache lock held.. */
+ spin_lock(&pagecache_lock);
+ if (page_count(page) - !!page->buffers == 2) {
+ __delete_from_swap_cache(page);
+ SetPageDirty(page);
+ retval = 1;
+ }
+ spin_unlock(&pagecache_lock);
+ }
+ swap_info_put(p);
+
+ if (retval) {
+ block_flushpage(page, 0);
+ swap_free(entry);
+ page_cache_release(page);
+ }
+
+ return retval;
+}
+
+/*
+ * Free the swap entry like above, but also try to
+ * free the page cache entry if it is the last user.
+ */
+void free_swap_and_cache(swp_entry_t entry)
+{
+ struct swap_info_struct * p;
+ struct page *page = NULL;
+
+ p = swap_info_get(entry);
+ if (p) {
+ if (swap_entry_free(p, SWP_OFFSET(entry)) == 1)
+ page = find_trylock_page(&swapper_space, entry.val);
+ swap_info_put(p);
+ }
+ if (page) {
+ page_cache_get(page);
+ /* Only cache user (+us), or swap space full? Free it! */
+ if (page_count(page) - !!page->buffers == 2 || vm_swap_full()) {
+ delete_from_swap_cache(page);
+ SetPageDirty(page);
+ }
+ UnlockPage(page);
+ page_cache_release(page);
+ }
+}
+
+/*
+ * The swap entry has been read in advance, and we return 1 to indicate
+ * that the page has been used or is no longer needed.
+ *
+ * Always set the resulting pte to be nowrite (the same as COW pages
+ * after one process has exited). We don't know just how many PTEs will
+ * share this swap entry, so be cautious and let do_wp_page work out
+ * what to do if a write is requested later.
+ */
+/* mmlist_lock and vma->vm_mm->page_table_lock are held */
+static inline void unuse_pte(struct vm_area_struct * vma, unsigned long address,
+ pte_t *dir, swp_entry_t entry, struct page* page)
+{
+ pte_t pte = *dir;
+
+ if (likely(pte_to_swp_entry(pte).val != entry.val))
+ return;
+ if (unlikely(pte_none(pte) || pte_present(pte)))
+ return;
+ get_page(page);
+ set_pte(dir, pte_mkold(mk_pte(page, vma->vm_page_prot)));
+ swap_free(entry);
+ ++vma->vm_mm->rss;
+}
+
+/* mmlist_lock and vma->vm_mm->page_table_lock are held */
+static inline void unuse_pmd(struct vm_area_struct * vma, pmd_t *dir,
+ unsigned long address, unsigned long size, unsigned long offset,
+ swp_entry_t entry, struct page* page)
+{
+ pte_t * pte;
+ unsigned long end;
+
+ if (pmd_none(*dir))
+ return;
+ if (pmd_bad(*dir)) {
+ pmd_ERROR(*dir);
+ pmd_clear(dir);
+ return;
+ }
+ pte = pte_offset(dir, address);
+ offset += address & PMD_MASK;
+ address &= ~PMD_MASK;
+ end = address + size;
+ if (end > PMD_SIZE)
+ end = PMD_SIZE;
+ do {
+ unuse_pte(vma, offset+address-vma->vm_start, pte, entry, page);
+ address += PAGE_SIZE;
+ pte++;
+ } while (address && (address < end));
+}
+
+/* mmlist_lock and vma->vm_mm->page_table_lock are held */
+static inline void unuse_pgd(struct vm_area_struct * vma, pgd_t *dir,
+ unsigned long address, unsigned long size,
+ swp_entry_t entry, struct page* page)
+{
+ pmd_t * pmd;
+ unsigned long offset, end;
+
+ if (pgd_none(*dir))
+ return;
+ if (pgd_bad(*dir)) {
+ pgd_ERROR(*dir);
+ pgd_clear(dir);
+ return;
+ }
+ pmd = pmd_offset(dir, address);
+ offset = address & PGDIR_MASK;
+ address &= ~PGDIR_MASK;
+ end = address + size;
+ if (end > PGDIR_SIZE)
+ end = PGDIR_SIZE;
+ if (address >= end)
+ BUG();
+ do {
+ unuse_pmd(vma, pmd, address, end - address, offset, entry,
+ page);
+ address = (address + PMD_SIZE) & PMD_MASK;
+ pmd++;
+ } while (address && (address < end));
+}
+
+/* mmlist_lock and vma->vm_mm->page_table_lock are held */
+static void unuse_vma(struct vm_area_struct * vma, pgd_t *pgdir,
+ swp_entry_t entry, struct page* page)
+{
+ unsigned long start = vma->vm_start, end = vma->vm_end;
+
+ if (start >= end)
+ BUG();
+ do {
+ unuse_pgd(vma, pgdir, start, end - start, entry, page);
+ start = (start + PGDIR_SIZE) & PGDIR_MASK;
+ pgdir++;
+ } while (start && (start < end));
+}
+
+static void unuse_process(struct mm_struct * mm,
+ swp_entry_t entry, struct page* page)
+{
+ struct vm_area_struct* vma;
+
+ /*
+ * Go through process' page directory.
+ */
+ spin_lock(&mm->page_table_lock);
+ for (vma = mm->mmap; vma; vma = vma->vm_next) {
+ pgd_t * pgd = pgd_offset(mm, vma->vm_start);
+ unuse_vma(vma, pgd, entry, page);
+ }
+ XENO_flush_page_update_queue();
+ spin_unlock(&mm->page_table_lock);
+ return;
+}
+
+/*
+ * Scan swap_map from current position to next entry still in use.
+ * Recycle to start on reaching the end, returning 0 when empty.
+ */
+static int find_next_to_unuse(struct swap_info_struct *si, int prev)
+{
+ int max = si->max;
+ int i = prev;
+ int count;
+
+ /*
+ * No need for swap_device_lock(si) here: we're just looking
+ * for whether an entry is in use, not modifying it; false
+ * hits are okay, and sys_swapoff() has already prevented new
+ * allocations from this area (while holding swap_list_lock()).
+ */
+ for (;;) {
+ if (++i >= max) {
+ if (!prev) {
+ i = 0;
+ break;
+ }
+ /*
+ * No entries in use at top of swap_map,
+ * loop back to start and recheck there.
+ */
+ max = prev + 1;
+ prev = 0;
+ i = 1;
+ }
+ count = si->swap_map[i];
+ if (count && count != SWAP_MAP_BAD)
+ break;
+ }
+ return i;
+}
+
+/*
+ * We completely avoid races by reading each swap page in advance,
+ * and then search for the process using it. All the necessary
+ * page table adjustments can then be made atomically.
+ */
+static int try_to_unuse(unsigned int type)
+{
+ struct swap_info_struct * si = &swap_info[type];
+ struct mm_struct *start_mm;
+ unsigned short *swap_map;
+ unsigned short swcount;
+ struct page *page;
+ swp_entry_t entry;
+ int i = 0;
+ int retval = 0;
+ int reset_overflow = 0;
+
+ /*
+ * When searching mms for an entry, a good strategy is to
+ * start at the first mm we freed the previous entry from
+ * (though actually we don't notice whether we or coincidence
+ * freed the entry). Initialize this start_mm with a hold.
+ *
+ * A simpler strategy would be to start at the last mm we
+ * freed the previous entry from; but that would take less
+ * advantage of mmlist ordering (now preserved by swap_out()),
+ * which clusters forked address spaces together, most recent
+ * child immediately after parent. If we race with dup_mmap(),
+ * we very much want to resolve parent before child, otherwise
+ * we may miss some entries: using last mm would invert that.
+ */
+ start_mm = &init_mm;
+ atomic_inc(&init_mm.mm_users);
+
+ /*
+ * Keep on scanning until all entries have gone. Usually,
+ * one pass through swap_map is enough, but not necessarily:
+ * mmput() removes mm from mmlist before exit_mmap() and its
+ * zap_page_range(). That's not too bad, those entries are
+ * on their way out, and handled faster there than here.
+ * do_munmap() behaves similarly, taking the range out of mm's
+ * vma list before zap_page_range(). But unfortunately, when
+ * unmapping a part of a vma, it takes the whole out first,
+ * then reinserts what's left after (might even reschedule if
+ * open() method called) - so swap entries may be invisible
+ * to swapoff for a while, then reappear - but that is rare.
+ */
+ while ((i = find_next_to_unuse(si, i))) {
+ /*
+ * Get a page for the entry, using the existing swap
+ * cache page if there is one. Otherwise, get a clean
+ * page and read the swap into it.
+ */
+ swap_map = &si->swap_map[i];
+ entry = SWP_ENTRY(type, i);
+ page = read_swap_cache_async(entry);
+ if (!page) {
+ /*
+ * Either swap_duplicate() failed because entry
+ * has been freed independently, and will not be
+ * reused since sys_swapoff() already disabled
+ * allocation from here, or alloc_page() failed.
+ */
+ if (!*swap_map)
+ continue;
+ retval = -ENOMEM;
+ break;
+ }
+
+ /*
+ * Don't hold on to start_mm if it looks like exiting.
+ */
+ if (atomic_read(&start_mm->mm_users) == 1) {
+ mmput(start_mm);
+ start_mm = &init_mm;
+ atomic_inc(&init_mm.mm_users);
+ }
+
+ /*
+ * Wait for and lock page. When do_swap_page races with
+ * try_to_unuse, do_swap_page can handle the fault much
+ * faster than try_to_unuse can locate the entry. This
+ * apparently redundant "wait_on_page" lets try_to_unuse
+ * defer to do_swap_page in such a case - in some tests,
+ * do_swap_page and try_to_unuse repeatedly compete.
+ */
+ wait_on_page(page);
+ lock_page(page);
+
+ /*
+ * Remove all references to entry, without blocking.
+ * Whenever we reach init_mm, there's no address space
+ * to search, but use it as a reminder to search shmem.
+ */
+ swcount = *swap_map;
+ if (swcount > 1) {
+ flush_page_to_ram(page);
+ if (start_mm == &init_mm)
+ shmem_unuse(entry, page);
+ else
+ unuse_process(start_mm, entry, page);
+ }
+ if (*swap_map > 1) {
+ int set_start_mm = (*swap_map >= swcount);
+ struct list_head *p = &start_mm->mmlist;
+ struct mm_struct *new_start_mm = start_mm;
+ struct mm_struct *mm;
+
+ spin_lock(&mmlist_lock);
+ while (*swap_map > 1 &&
+ (p = p->next) != &start_mm->mmlist) {
+ mm = list_entry(p, struct mm_struct, mmlist);
+ swcount = *swap_map;
+ if (mm == &init_mm) {
+ set_start_mm = 1;
+ shmem_unuse(entry, page);
+ } else
+ unuse_process(mm, entry, page);
+ if (set_start_mm && *swap_map < swcount) {
+ new_start_mm = mm;
+ set_start_mm = 0;
+ }
+ }
+ atomic_inc(&new_start_mm->mm_users);
+ spin_unlock(&mmlist_lock);
+ mmput(start_mm);
+ start_mm = new_start_mm;
+ }
+
+ /*
+ * How could swap count reach 0x7fff when the maximum
+ * pid is 0x7fff, and there's no way to repeat a swap
+ * page within an mm (except in shmem, where it's the
+ * shared object which takes the reference count)?
+ * We believe SWAP_MAP_MAX cannot occur in Linux 2.4.
+ *
+ * If that's wrong, then we should worry more about
+ * exit_mmap() and do_munmap() cases described above:
+ * we might be resetting SWAP_MAP_MAX too early here.
+ * We know "Undead"s can happen, they're okay, so don't
+ * report them; but do report if we reset SWAP_MAP_MAX.
+ */
+ if (*swap_map == SWAP_MAP_MAX) {
+ swap_list_lock();
+ swap_device_lock(si);
+ nr_swap_pages++;
+ *swap_map = 1;
+ swap_device_unlock(si);
+ swap_list_unlock();
+ reset_overflow = 1;
+ }
+
+ /*
+ * If a reference remains (rare), we would like to leave
+ * the page in the swap cache; but try_to_swap_out could
+ * then re-duplicate the entry once we drop page lock,
+ * so we might loop indefinitely; also, that page could
+ * not be swapped out to other storage meanwhile. So:
+ * delete from cache even if there's another reference,
+ * after ensuring that the data has been saved to disk -
+ * since if the reference remains (rarer), it will be
+ * read from disk into another page. Splitting into two
+ * pages would be incorrect if swap supported "shared
+ * private" pages, but they are handled by tmpfs files.
+ * Note shmem_unuse already deleted its from swap cache.
+ */
+ if ((*swap_map > 1) && PageDirty(page) && PageSwapCache(page)) {
+ rw_swap_page(WRITE, page);
+ lock_page(page);
+ }
+ if (PageSwapCache(page))
+ delete_from_swap_cache(page);
+
+ /*
+ * So we could skip searching mms once swap count went
+ * to 1, we did not mark any present ptes as dirty: must
+ * mark page dirty so try_to_swap_out will preserve it.
+ */
+ SetPageDirty(page);
+ UnlockPage(page);
+ page_cache_release(page);
+
+ /*
+ * Make sure that we aren't completely killing
+ * interactive performance. Interruptible check on
+ * signal_pending() would be nice, but changes the spec?
+ */
+ if (current->need_resched)
+ schedule();
+ }
+
+ mmput(start_mm);
+ if (reset_overflow) {
+ printk(KERN_WARNING "swapoff: cleared swap entry overflow\n");
+ swap_overflow = 0;
+ }
+ return retval;
+}
+
+asmlinkage long sys_swapoff(const char * specialfile)
+{
+ struct swap_info_struct * p = NULL;
+ unsigned short *swap_map;
+ struct nameidata nd;
+ int i, type, prev;
+ int err;
+
+ if (!capable(CAP_SYS_ADMIN))
+ return -EPERM;
+
+ err = user_path_walk(specialfile, &nd);
+ if (err)
+ goto out;
+
+ lock_kernel();
+ prev = -1;
+ swap_list_lock();
+ for (type = swap_list.head; type >= 0; type = swap_info[type].next) {
+ p = swap_info + type;
+ if ((p->flags & SWP_WRITEOK) == SWP_WRITEOK) {
+ if (p->swap_file == nd.dentry)
+ break;
+ }
+ prev = type;
+ }
+ err = -EINVAL;
+ if (type < 0) {
+ swap_list_unlock();
+ goto out_dput;
+ }
+
+ if (prev < 0) {
+ swap_list.head = p->next;
+ } else {
+ swap_info[prev].next = p->next;
+ }
+ if (type == swap_list.next) {
+ /* just pick something that's safe... */
+ swap_list.next = swap_list.head;
+ }
+ nr_swap_pages -= p->pages;
+ total_swap_pages -= p->pages;
+ p->flags = SWP_USED;
+ swap_list_unlock();
+ unlock_kernel();
+ err = try_to_unuse(type);
+ lock_kernel();
+ if (err) {
+ /* re-insert swap space back into swap_list */
+ swap_list_lock();
+ for (prev = -1, i = swap_list.head; i >= 0; prev = i, i = swap_info[i].next)
+ if (p->prio >= swap_info[i].prio)
+ break;
+ p->next = i;
+ if (prev < 0)
+ swap_list.head = swap_list.next = p - swap_info;
+ else
+ swap_info[prev].next = p - swap_info;
+ nr_swap_pages += p->pages;
+ total_swap_pages += p->pages;
+ p->flags = SWP_WRITEOK;
+ swap_list_unlock();
+ goto out_dput;
+ }
+ if (p->swap_device)
+ blkdev_put(p->swap_file->d_inode->i_bdev, BDEV_SWAP);
+ path_release(&nd);
+
+ swap_list_lock();
+ swap_device_lock(p);
+ nd.mnt = p->swap_vfsmnt;
+ nd.dentry = p->swap_file;
+ p->swap_vfsmnt = NULL;
+ p->swap_file = NULL;
+ p->swap_device = 0;
+ p->max = 0;
+ swap_map = p->swap_map;
+ p->swap_map = NULL;
+ p->flags = 0;
+ swap_device_unlock(p);
+ swap_list_unlock();
+ vfree(swap_map);
+ err = 0;
+
+out_dput:
+ unlock_kernel();
+ path_release(&nd);
+out:
+ return err;
+}
+
+int get_swaparea_info(char *buf)
+{
+ char * page = (char *) __get_free_page(GFP_KERNEL);
+ struct swap_info_struct *ptr = swap_info;
+ int i, j, len = 0, usedswap;
+
+ if (!page)
+ return -ENOMEM;
+
+ len += sprintf(buf, "Filename\t\t\tType\t\tSize\tUsed\tPriority\n");
+ for (i = 0 ; i < nr_swapfiles ; i++, ptr++) {
+ if ((ptr->flags & SWP_USED) && ptr->swap_map) {
+ char * path = d_path(ptr->swap_file, ptr->swap_vfsmnt,
+ page, PAGE_SIZE);
+
+ len += sprintf(buf + len, "%-31s ", path);
+
+ if (!ptr->swap_device)
+ len += sprintf(buf + len, "file\t\t");
+ else
+ len += sprintf(buf + len, "partition\t");
+
+ usedswap = 0;
+ for (j = 0; j < ptr->max; ++j)
+ switch (ptr->swap_map[j]) {
+ case SWAP_MAP_BAD:
+ case 0:
+ continue;
+ default:
+ usedswap++;
+ }
+ len += sprintf(buf + len, "%d\t%d\t%d\n", ptr->pages << (PAGE_SHIFT - 10),
+ usedswap << (PAGE_SHIFT - 10), ptr->prio);
+ }
+ }
+ free_page((unsigned long) page);
+ return len;
+}
+
+int is_swap_partition(kdev_t dev) {
+ struct swap_info_struct *ptr = swap_info;
+ int i;
+
+ for (i = 0 ; i < nr_swapfiles ; i++, ptr++) {
+ if (ptr->flags & SWP_USED)
+ if (ptr->swap_device == dev)
+ return 1;
+ }
+ return 0;
+}
+
+/*
+ * Written 01/25/92 by Simmule Turner, heavily changed by Linus.
+ *
+ * The swapon system call
+ */
+asmlinkage long sys_swapon(const char * specialfile, int swap_flags)
+{
+ struct swap_info_struct * p;
+ struct nameidata nd;
+ struct inode * swap_inode;
+ unsigned int type;
+ int i, j, prev;
+ int error;
+ static int least_priority = 0;
+ union swap_header *swap_header = 0;
+ int swap_header_version;
+ int nr_good_pages = 0;
+ unsigned long maxpages = 1;
+ int swapfilesize;
+ struct block_device *bdev = NULL;
+ unsigned short *swap_map;
+
+ if (!capable(CAP_SYS_ADMIN))
+ return -EPERM;
+ lock_kernel();
+ swap_list_lock();
+ p = swap_info;
+ for (type = 0 ; type < nr_swapfiles ; type++,p++)
+ if (!(p->flags & SWP_USED))
+ break;
+ error = -EPERM;
+ if (type >= MAX_SWAPFILES) {
+ swap_list_unlock();
+ goto out;
+ }
+ if (type >= nr_swapfiles)
+ nr_swapfiles = type+1;
+ p->flags = SWP_USED;
+ p->swap_file = NULL;
+ p->swap_vfsmnt = NULL;
+ p->swap_device = 0;
+ p->swap_map = NULL;
+ p->lowest_bit = 0;
+ p->highest_bit = 0;
+ p->cluster_nr = 0;
+ p->sdev_lock = SPIN_LOCK_UNLOCKED;
+ p->next = -1;
+ if (swap_flags & SWAP_FLAG_PREFER) {
+ p->prio =
+ (swap_flags & SWAP_FLAG_PRIO_MASK)>>SWAP_FLAG_PRIO_SHIFT;
+ } else {
+ p->prio = --least_priority;
+ }
+ swap_list_unlock();
+ error = user_path_walk(specialfile, &nd);
+ if (error)
+ goto bad_swap_2;
+
+ p->swap_file = nd.dentry;
+ p->swap_vfsmnt = nd.mnt;
+ swap_inode = nd.dentry->d_inode;
+ error = -EINVAL;
+
+ if (S_ISBLK(swap_inode->i_mode)) {
+ kdev_t dev = swap_inode->i_rdev;
+ struct block_device_operations *bdops;
+ devfs_handle_t de;
+
+ if (is_mounted(dev)) {
+ error = -EBUSY;
+ goto bad_swap_2;
+ }
+
+ p->swap_device = dev;
+ set_blocksize(dev, PAGE_SIZE);
+
+ bd_acquire(swap_inode);
+ bdev = swap_inode->i_bdev;
+ de = devfs_get_handle_from_inode(swap_inode);
+ bdops = devfs_get_ops(de); /* Increments module use count */
+ if (bdops) bdev->bd_op = bdops;
+
+ error = blkdev_get(bdev, FMODE_READ|FMODE_WRITE, 0, BDEV_SWAP);
+ devfs_put_ops(de);/*Decrement module use count now we're safe*/
+ if (error)
+ goto bad_swap_2;
+ set_blocksize(dev, PAGE_SIZE);
+ error = -ENODEV;
+ if (!dev || (blk_size[MAJOR(dev)] &&
+ !blk_size[MAJOR(dev)][MINOR(dev)]))
+ goto bad_swap;
+ swapfilesize = 0;
+ if (blk_size[MAJOR(dev)])
+ swapfilesize = blk_size[MAJOR(dev)][MINOR(dev)]
+ >> (PAGE_SHIFT - 10);
+ } else if (S_ISREG(swap_inode->i_mode))
+ swapfilesize = swap_inode->i_size >> PAGE_SHIFT;
+ else
+ goto bad_swap;
+
+ error = -EBUSY;
+ for (i = 0 ; i < nr_swapfiles ; i++) {
+ struct swap_info_struct *q = &swap_info[i];
+ if (i == type || !q->swap_file)
+ continue;
+ if (swap_inode->i_mapping == q->swap_file->d_inode->i_mapping)
+ goto bad_swap;
+ }
+
+ swap_header = (void *) __get_free_page(GFP_USER);
+ if (!swap_header) {
+ printk("Unable to start swapping: out of memory :-)\n");
+ error = -ENOMEM;
+ goto bad_swap;
+ }
+
+ lock_page(virt_to_page(swap_header));
+ rw_swap_page_nolock(READ, SWP_ENTRY(type,0), (char *) swap_header);
+
+ if (!memcmp("SWAP-SPACE",swap_header->magic.magic,10))
+ swap_header_version = 1;
+ else if (!memcmp("SWAPSPACE2",swap_header->magic.magic,10))
+ swap_header_version = 2;
+ else {
+ printk("Unable to find swap-space signature\n");
+ error = -EINVAL;
+ goto bad_swap;
+ }
+
+ switch (swap_header_version) {
+ case 1:
+ memset(((char *) swap_header)+PAGE_SIZE-10,0,10);
+ j = 0;
+ p->lowest_bit = 0;
+ p->highest_bit = 0;
+ for (i = 1 ; i < 8*PAGE_SIZE ; i++) {
+ if (test_bit(i,(char *) swap_header)) {
+ if (!p->lowest_bit)
+ p->lowest_bit = i;
+ p->highest_bit = i;
+ maxpages = i+1;
+ j++;
+ }
+ }
+ nr_good_pages = j;
+ p->swap_map = vmalloc(maxpages * sizeof(short));
+ if (!p->swap_map) {
+ error = -ENOMEM;
+ goto bad_swap;
+ }
+ for (i = 1 ; i < maxpages ; i++) {
+ if (test_bit(i,(char *) swap_header))
+ p->swap_map[i] = 0;
+ else
+ p->swap_map[i] = SWAP_MAP_BAD;
+ }
+ break;
+
+ case 2:
+ /* Check the swap header's sub-version and the size of
+ the swap file and bad block lists */
+ if (swap_header->info.version != 1) {
+ printk(KERN_WARNING
+ "Unable to handle swap header version %d\n",
+ swap_header->info.version);
+ error = -EINVAL;
+ goto bad_swap;
+ }
+
+ p->lowest_bit = 1;
+ maxpages = SWP_OFFSET(SWP_ENTRY(0,~0UL)) - 1;
+ if (maxpages > swap_header->info.last_page)
+ maxpages = swap_header->info.last_page;
+ p->highest_bit = maxpages - 1;
+
+ error = -EINVAL;
+ if (swap_header->info.nr_badpages > MAX_SWAP_BADPAGES)
+ goto bad_swap;
+
+ /* OK, set up the swap map and apply the bad block list */
+ if (!(p->swap_map = vmalloc(maxpages * sizeof(short)))) {
+ error = -ENOMEM;
+ goto bad_swap;
+ }
+
+ error = 0;
+ memset(p->swap_map, 0, maxpages * sizeof(short));
+ for (i=0; i<swap_header->info.nr_badpages; i++) {
+ int page = swap_header->info.badpages[i];
+ if (page <= 0 || page >= swap_header->info.last_page)
+ error = -EINVAL;
+ else
+ p->swap_map[page] = SWAP_MAP_BAD;
+ }
+ nr_good_pages = swap_header->info.last_page -
+ swap_header->info.nr_badpages -
+ 1 /* header page */;
+ if (error)
+ goto bad_swap;
+ }
+
+ if (swapfilesize && maxpages > swapfilesize) {
+ printk(KERN_WARNING
+ "Swap area shorter than signature indicates\n");
+ error = -EINVAL;
+ goto bad_swap;
+ }
+ if (!nr_good_pages) {
+ printk(KERN_WARNING "Empty swap-file\n");
+ error = -EINVAL;
+ goto bad_swap;
+ }
+ p->swap_map[0] = SWAP_MAP_BAD;
+ swap_list_lock();
+ swap_device_lock(p);
+ p->max = maxpages;
+ p->flags = SWP_WRITEOK;
+ p->pages = nr_good_pages;
+ nr_swap_pages += nr_good_pages;
+ total_swap_pages += nr_good_pages;
+ printk(KERN_INFO "Adding Swap: %dk swap-space (priority %d)\n",
+ nr_good_pages<<(PAGE_SHIFT-10), p->prio);
+
+ /* insert swap space into swap_list: */
+ prev = -1;
+ for (i = swap_list.head; i >= 0; i = swap_info[i].next) {
+ if (p->prio >= swap_info[i].prio) {
+ break;
+ }
+ prev = i;
+ }
+ p->next = i;
+ if (prev < 0) {
+ swap_list.head = swap_list.next = p - swap_info;
+ } else {
+ swap_info[prev].next = p - swap_info;
+ }
+ swap_device_unlock(p);
+ swap_list_unlock();
+ error = 0;
+ goto out;
+bad_swap:
+ if (bdev)
+ blkdev_put(bdev, BDEV_SWAP);
+bad_swap_2:
+ swap_list_lock();
+ swap_map = p->swap_map;
+ nd.mnt = p->swap_vfsmnt;
+ nd.dentry = p->swap_file;
+ p->swap_device = 0;
+ p->swap_file = NULL;
+ p->swap_vfsmnt = NULL;
+ p->swap_map = NULL;
+ p->flags = 0;
+ if (!(swap_flags & SWAP_FLAG_PREFER))
+ ++least_priority;
+ swap_list_unlock();
+ if (swap_map)
+ vfree(swap_map);
+ path_release(&nd);
+out:
+ if (swap_header)
+ free_page((long) swap_header);
+ unlock_kernel();
+ return error;
+}
+
+void si_swapinfo(struct sysinfo *val)
+{
+ unsigned int i;
+ unsigned long nr_to_be_unused = 0;
+
+ swap_list_lock();
+ for (i = 0; i < nr_swapfiles; i++) {
+ unsigned int j;
+ if (swap_info[i].flags != SWP_USED)
+ continue;
+ for (j = 0; j < swap_info[i].max; ++j) {
+ switch (swap_info[i].swap_map[j]) {
+ case 0:
+ case SWAP_MAP_BAD:
+ continue;
+ default:
+ nr_to_be_unused++;
+ }
+ }
+ }
+ val->freeswap = nr_swap_pages + nr_to_be_unused;
+ val->totalswap = total_swap_pages + nr_to_be_unused;
+ swap_list_unlock();
+}
+
+/*
+ * Verify that a swap entry is valid and increment its swap map count.
+ *
+ * Note: if swap_map[] reaches SWAP_MAP_MAX the entries are treated as
+ * "permanent", but will be reclaimed by the next swapoff.
+ */
+int swap_duplicate(swp_entry_t entry)
+{
+ struct swap_info_struct * p;
+ unsigned long offset, type;
+ int result = 0;
+
+ type = SWP_TYPE(entry);
+ if (type >= nr_swapfiles)
+ goto bad_file;
+ p = type + swap_info;
+ offset = SWP_OFFSET(entry);
+
+ swap_device_lock(p);
+ if (offset < p->max && p->swap_map[offset]) {
+ if (p->swap_map[offset] < SWAP_MAP_MAX - 1) {
+ p->swap_map[offset]++;
+ result = 1;
+ } else if (p->swap_map[offset] <= SWAP_MAP_MAX) {
+ if (swap_overflow++ < 5)
+ printk(KERN_WARNING "swap_dup: swap entry overflow\n");
+ p->swap_map[offset] = SWAP_MAP_MAX;
+ result = 1;
+ }
+ }
+ swap_device_unlock(p);
+out:
+ return result;
+
+bad_file:
+ printk(KERN_ERR "swap_dup: %s%08lx\n", Bad_file, entry.val);
+ goto out;
+}
+
+/*
+ * Prior swap_duplicate protects against swap device deletion.
+ */
+void get_swaphandle_info(swp_entry_t entry, unsigned long *offset,
+ kdev_t *dev, struct inode **swapf)
+{
+ unsigned long type;
+ struct swap_info_struct *p;
+
+ type = SWP_TYPE(entry);
+ if (type >= nr_swapfiles) {
+ printk(KERN_ERR "rw_swap_page: %s%08lx\n", Bad_file, entry.val);
+ return;
+ }
+
+ p = &swap_info[type];
+ *offset = SWP_OFFSET(entry);
+ if (*offset >= p->max && *offset != 0) {
+ printk(KERN_ERR "rw_swap_page: %s%08lx\n", Bad_offset, entry.val);
+ return;
+ }
+ if (p->swap_map && !p->swap_map[*offset]) {
+ printk(KERN_ERR "rw_swap_page: %s%08lx\n", Unused_offset, entry.val);
+ return;
+ }
+ if (!(p->flags & SWP_USED)) {
+ printk(KERN_ERR "rw_swap_page: %s%08lx\n", Unused_file, entry.val);
+ return;
+ }
+
+ if (p->swap_device) {
+ *dev = p->swap_device;
+ } else if (p->swap_file) {
+ *swapf = p->swap_file->d_inode;
+ } else {
+ printk(KERN_ERR "rw_swap_page: no swap file or device\n");
+ }
+ return;
+}
+
+/*
+ * swap_device_lock prevents swap_map being freed. Don't grab an extra
+ * reference on the swaphandle, it doesn't matter if it becomes unused.
+ */
+int valid_swaphandles(swp_entry_t entry, unsigned long *offset)
+{
+ int ret = 0, i = 1 << page_cluster;
+ unsigned long toff;
+ struct swap_info_struct *swapdev = SWP_TYPE(entry) + swap_info;
+
+ if (!page_cluster) /* no readahead */
+ return 0;
+ toff = (SWP_OFFSET(entry) >> page_cluster) << page_cluster;
+ if (!toff) /* first page is swap header */
+ toff++, i--;
+ *offset = toff;
+
+ swap_device_lock(swapdev);
+ do {
+ /* Don't read-ahead past the end of the swap area */
+ if (toff >= swapdev->max)
+ break;
+ /* Don't read in free or bad pages */
+ if (!swapdev->swap_map[toff])
+ break;
+ if (swapdev->swap_map[toff] == SWAP_MAP_BAD)
+ break;
+ toff++;
+ ret++;
+ } while (--i);
+ swap_device_unlock(swapdev);
+ return ret;
+}